opentelemetry_proto/
common.rs

1use bytes::Bytes;
2use ordered_float::NotNan;
3use vector_core::event::metric::TagValue;
4use vrl::value::{ObjectMap, Value};
5
6use super::proto::common::v1::{KeyValue, any_value::Value as PBValue};
7
8impl From<PBValue> for Value {
9    fn from(av: PBValue) -> Self {
10        match av {
11            PBValue::StringValue(v) => Value::Bytes(Bytes::from(v)),
12            PBValue::BoolValue(v) => Value::Boolean(v),
13            PBValue::IntValue(v) => Value::Integer(v),
14            PBValue::DoubleValue(v) => NotNan::new(v).map(Value::Float).unwrap_or(Value::Null),
15            PBValue::BytesValue(v) => Value::Bytes(Bytes::from(v)),
16            PBValue::ArrayValue(arr) => Value::Array(
17                arr.values
18                    .into_iter()
19                    .map(|av| av.value.map(Into::into).unwrap_or(Value::Null))
20                    .collect::<Vec<Value>>(),
21            ),
22            PBValue::KvlistValue(arr) => kv_list_into_value(arr.values),
23        }
24    }
25}
26
27impl From<PBValue> for TagValue {
28    fn from(pb: PBValue) -> Self {
29        match pb {
30            PBValue::StringValue(s) => TagValue::from(s),
31            PBValue::BoolValue(b) => TagValue::from(b.to_string()),
32            PBValue::IntValue(i) => TagValue::from(i.to_string()),
33            PBValue::DoubleValue(f) => TagValue::from(f.to_string()),
34            PBValue::BytesValue(b) => TagValue::from(String::from_utf8_lossy(&b).to_string()),
35            _ => TagValue::from("null"),
36        }
37    }
38}
39
40pub fn kv_list_into_value(arr: Vec<KeyValue>) -> Value {
41    Value::Object(
42        arr.into_iter()
43            .filter_map(|kv| {
44                kv.value.map(|av| {
45                    (
46                        kv.key.into(),
47                        av.value.map(Into::into).unwrap_or(Value::Null),
48                    )
49                })
50            })
51            .collect::<ObjectMap>(),
52    )
53}
54
55pub fn to_hex(d: &[u8]) -> String {
56    if d.is_empty() {
57        return "".to_string();
58    }
59    hex::encode(d)
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_pb_double_value_nan_handling() {
68        // Test that NaN values are converted to Value::Null instead of panicking
69        let nan_value = PBValue::DoubleValue(f64::NAN);
70        let result = Value::from(nan_value);
71        assert_eq!(result, Value::Null);
72    }
73
74    #[test]
75    fn test_pb_double_value_infinity() {
76        // Test that infinity values work correctly
77        let inf_value = PBValue::DoubleValue(f64::INFINITY);
78        let result = Value::from(inf_value);
79        match result {
80            Value::Float(f) => {
81                assert!(f.into_inner().is_infinite() && f.into_inner().is_sign_positive())
82            }
83            _ => panic!("Expected Float value, got {result:?}"),
84        }
85
86        let neg_inf_value = PBValue::DoubleValue(f64::NEG_INFINITY);
87        let result = Value::from(neg_inf_value);
88        match result {
89            Value::Float(f) => {
90                assert!(f.into_inner().is_infinite() && f.into_inner().is_sign_negative())
91            }
92            _ => panic!("Expected Float value, got {result:?}"),
93        }
94    }
95}