opentelemetry_proto/
common.rs

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