Skip to main content

opentelemetry_proto/
common.rs

1use bytes::Bytes;
2use ordered_float::NotNan;
3use vector_core::event::metric::{TagValue, TagValueSet};
4use vrl::value::{ObjectMap, Value};
5
6use super::proto::common::v1::{AnyValue, ArrayValue, 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
40impl From<TagValue> for AnyValue {
41    fn from(tag: TagValue) -> Self {
42        match tag {
43            TagValue::Value(s) => Self {
44                value: Some(PBValue::StringValue(s)),
45            },
46            TagValue::Bare => Self { value: None },
47        }
48    }
49}
50
51pub fn str_to_key_value(key: &str, val: TagValue) -> KeyValue {
52    KeyValue {
53        key: key.to_string(),
54        value: Some(val.into()),
55    }
56}
57
58pub fn tag_set_to_any_value(tag_set: TagValueSet) -> Option<AnyValue> {
59    match tag_set {
60        TagValueSet::Empty => None,
61        TagValueSet::Single(tag) => Some(tag.into()),
62        TagValueSet::Set(set) => Some(AnyValue {
63            value: Some(PBValue::ArrayValue(ArrayValue {
64                values: set.into_iter().map(Into::into).collect(),
65            })),
66        }),
67    }
68}
69
70pub fn kv_list_into_value(arr: Vec<KeyValue>) -> Value {
71    Value::Object(
72        arr.into_iter()
73            .filter_map(|kv| {
74                kv.value.map(|av| {
75                    (
76                        kv.key.into(),
77                        av.value.map(Into::into).unwrap_or(Value::Null),
78                    )
79                })
80            })
81            .collect::<ObjectMap>(),
82    )
83}
84
85pub fn to_hex(d: &[u8]) -> String {
86    if d.is_empty() {
87        return "".to_string();
88    }
89    hex::encode(d)
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn test_pb_double_value_nan_handling() {
98        // Test that NaN values are converted to Value::Null instead of panicking
99        let nan_value = PBValue::DoubleValue(f64::NAN);
100        let result = Value::from(nan_value);
101        assert_eq!(result, Value::Null);
102    }
103
104    #[test]
105    fn test_pb_double_value_infinity() {
106        // Test that infinity values work correctly
107        let inf_value = PBValue::DoubleValue(f64::INFINITY);
108        let result = Value::from(inf_value);
109        match result {
110            Value::Float(f) => {
111                assert!(f.into_inner().is_infinite() && f.into_inner().is_sign_positive())
112            }
113            _ => panic!("Expected Float value, got {result:?}"),
114        }
115
116        let neg_inf_value = PBValue::DoubleValue(f64::NEG_INFINITY);
117        let result = Value::from(neg_inf_value);
118        match result {
119            Value::Float(f) => {
120                assert!(f.into_inner().is_infinite() && f.into_inner().is_sign_negative())
121            }
122            _ => panic!("Expected Float value, got {result:?}"),
123        }
124    }
125}