opentelemetry_proto/transform/
common.rs

1#[cfg(all(
2    feature = "gen-tonic-messages",
3    any(feature = "trace", feature = "metrics", feature = "logs")
4))]
5use std::time::{Duration, SystemTime, UNIX_EPOCH};
6
7#[cfg(all(
8    feature = "gen-tonic-messages",
9    any(feature = "trace", feature = "metrics", feature = "logs")
10))]
11pub(crate) fn to_nanos(time: SystemTime) -> u64 {
12    time.duration_since(UNIX_EPOCH)
13        .unwrap_or_else(|_| Duration::from_secs(0))
14        .as_nanos() as u64
15}
16
17#[cfg(feature = "gen-tonic-messages")]
18pub mod tonic {
19    use crate::proto::tonic::common::v1::{
20        any_value, AnyValue, ArrayValue, InstrumentationScope, KeyValue,
21    };
22    use opentelemetry::{Array, Value};
23    use std::borrow::Cow;
24
25    #[cfg(any(feature = "trace", feature = "logs"))]
26    #[derive(Debug, Default)]
27    pub struct ResourceAttributesWithSchema {
28        pub attributes: Attributes,
29        pub schema_url: Option<String>,
30    }
31
32    #[cfg(any(feature = "trace", feature = "logs"))]
33    impl From<&opentelemetry_sdk::Resource> for ResourceAttributesWithSchema {
34        fn from(resource: &opentelemetry_sdk::Resource) -> Self {
35            ResourceAttributesWithSchema {
36                attributes: resource_attributes(resource),
37                schema_url: resource.schema_url().map(ToString::to_string),
38            }
39        }
40    }
41
42    #[cfg(any(feature = "trace", feature = "logs"))]
43    use opentelemetry_sdk::Resource;
44
45    impl
46        From<(
47            opentelemetry::InstrumentationScope,
48            Option<Cow<'static, str>>,
49        )> for InstrumentationScope
50    {
51        fn from(
52            data: (
53                opentelemetry::InstrumentationScope,
54                Option<Cow<'static, str>>,
55            ),
56        ) -> Self {
57            let (library, target) = data;
58            if let Some(t) = target {
59                InstrumentationScope {
60                    name: t.to_string(),
61                    version: String::new(),
62                    attributes: vec![],
63                    ..Default::default()
64                }
65            } else {
66                InstrumentationScope {
67                    name: library.name().to_owned(),
68                    version: library.version().map(ToOwned::to_owned).unwrap_or_default(),
69                    attributes: Attributes::from(library.attributes().cloned()).0,
70                    ..Default::default()
71                }
72            }
73        }
74    }
75
76    impl
77        From<(
78            &opentelemetry::InstrumentationScope,
79            Option<Cow<'static, str>>,
80        )> for InstrumentationScope
81    {
82        fn from(
83            data: (
84                &opentelemetry::InstrumentationScope,
85                Option<Cow<'static, str>>,
86            ),
87        ) -> Self {
88            let (library, target) = data;
89            if let Some(t) = target {
90                InstrumentationScope {
91                    name: t.to_string(),
92                    version: String::new(),
93                    attributes: vec![],
94                    ..Default::default()
95                }
96            } else {
97                InstrumentationScope {
98                    name: library.name().to_owned(),
99                    version: library.version().map(ToOwned::to_owned).unwrap_or_default(),
100                    attributes: Attributes::from(library.attributes().cloned()).0,
101                    ..Default::default()
102                }
103            }
104        }
105    }
106
107    /// Wrapper type for Vec<`KeyValue`>
108    #[derive(Default, Debug)]
109    pub struct Attributes(pub ::std::vec::Vec<crate::proto::tonic::common::v1::KeyValue>);
110
111    impl<I: IntoIterator<Item = opentelemetry::KeyValue>> From<I> for Attributes {
112        fn from(kvs: I) -> Self {
113            Attributes(
114                kvs.into_iter()
115                    .map(|api_kv| KeyValue {
116                        key: api_kv.key.as_str().to_string(),
117                        value: Some(api_kv.value.into()),
118                    })
119                    .collect(),
120            )
121        }
122    }
123
124    #[cfg(feature = "logs")]
125    impl<K: Into<String>, V: Into<AnyValue>> FromIterator<(K, V)> for Attributes {
126        fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
127            Attributes(
128                iter.into_iter()
129                    .map(|(k, v)| KeyValue {
130                        key: k.into(),
131                        value: Some(v.into()),
132                    })
133                    .collect(),
134            )
135        }
136    }
137
138    impl From<Value> for AnyValue {
139        fn from(value: Value) -> Self {
140            AnyValue {
141                value: match value {
142                    Value::Bool(val) => Some(any_value::Value::BoolValue(val)),
143                    Value::I64(val) => Some(any_value::Value::IntValue(val)),
144                    Value::F64(val) => Some(any_value::Value::DoubleValue(val)),
145                    Value::String(val) => Some(any_value::Value::StringValue(val.to_string())),
146                    Value::Array(array) => Some(any_value::Value::ArrayValue(match array {
147                        Array::Bool(vals) => array_into_proto(vals),
148                        Array::I64(vals) => array_into_proto(vals),
149                        Array::F64(vals) => array_into_proto(vals),
150                        Array::String(vals) => array_into_proto(vals),
151                        _ => unreachable!("Nonexistent array type"), // Needs to be updated when new array types are added
152                    })),
153                    _ => unreachable!("Nonexistent value type"), // Needs to be updated when new value types are added
154                },
155            }
156        }
157    }
158
159    fn array_into_proto<T>(vals: Vec<T>) -> ArrayValue
160    where
161        Value: From<T>,
162    {
163        let values = vals
164            .into_iter()
165            .map(|val| AnyValue::from(Value::from(val)))
166            .collect();
167
168        ArrayValue { values }
169    }
170
171    #[cfg(any(feature = "trace", feature = "logs"))]
172    pub(crate) fn resource_attributes(resource: &Resource) -> Attributes {
173        resource
174            .iter()
175            .map(|(k, v)| opentelemetry::KeyValue::new(k.clone(), v.clone()))
176            .collect::<Vec<_>>()
177            .into()
178    }
179}