aws_smithy_observability_otel/
attributes.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Utilities to transform back and forth from Smithy Observability [Attributes] to
7//! OTel [KeyValue]s.
8
9use std::ops::Deref;
10
11use aws_smithy_observability::{AttributeValue, Attributes};
12use opentelemetry::{KeyValue, Value};
13
14pub(crate) struct AttributesWrap(Attributes);
15impl AttributesWrap {
16    pub(crate) fn new(inner: Attributes) -> Self {
17        Self(inner)
18    }
19}
20impl Deref for AttributesWrap {
21    type Target = Attributes;
22
23    fn deref(&self) -> &Self::Target {
24        &self.0
25    }
26}
27
28pub(crate) fn kv_from_option_attr(input: Option<&Attributes>) -> Vec<KeyValue> {
29    input
30        .map(|attr| AttributesWrap::new(attr.clone()))
31        .unwrap_or(AttributesWrap::new(Attributes::new()))
32        .into()
33}
34
35#[allow(dead_code)]
36pub(crate) fn option_attr_from_kv(input: &[KeyValue]) -> Option<Attributes> {
37    if input.is_empty() {
38        return None;
39    }
40
41    Some(AttributesWrap::from(input).0)
42}
43
44impl From<AttributesWrap> for Vec<KeyValue> {
45    fn from(value: AttributesWrap) -> Self {
46        value
47            .0
48            .into_attributes()
49            .map(|(k, v)| {
50                KeyValue::new(
51                    k,
52                    match v {
53                        AttributeValue::I64(val) => Value::I64(val),
54                        AttributeValue::F64(val) => Value::F64(val),
55                        AttributeValue::String(val) => Value::String(val.into()),
56                        AttributeValue::Bool(val) => Value::Bool(val),
57                        _ => Value::String("UNSUPPORTED ATTRIBUTE VALUE TYPE".into()),
58                    },
59                )
60            })
61            .collect::<Vec<KeyValue>>()
62    }
63}
64
65impl From<&[KeyValue]> for AttributesWrap {
66    fn from(value: &[KeyValue]) -> Self {
67        let mut attrs = Attributes::new();
68
69        value.iter().for_each(|kv| {
70            attrs.set(
71                kv.key.clone(),
72                match &kv.value {
73                    Value::Bool(val) => AttributeValue::Bool(*val),
74                    Value::I64(val) => AttributeValue::I64(*val),
75                    Value::F64(val) => AttributeValue::F64(*val),
76                    Value::String(val) => AttributeValue::String(val.clone().into()),
77                    Value::Array(_) => {
78                        AttributeValue::String("UNSUPPORTED ATTRIBUTE VALUE TYPE".into())
79                    }
80                },
81            )
82        });
83
84        AttributesWrap(attrs)
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use std::collections::HashMap;
91
92    use super::*;
93    use aws_smithy_observability::{AttributeValue, Attributes};
94    use opentelemetry::Value;
95
96    #[test]
97    fn attr_to_kv() {
98        let mut attrs = Attributes::new();
99        attrs.set("I64", AttributeValue::I64(64));
100        attrs.set("F64", AttributeValue::F64(64.0));
101        attrs.set("String", AttributeValue::String("I AM A STRING".into()));
102        attrs.set("Bool", AttributeValue::Bool(true));
103
104        let kv = kv_from_option_attr(Some(&attrs));
105
106        let kv_map: HashMap<String, Value> = kv
107            .into_iter()
108            .map(|kv| (kv.key.to_string(), kv.value))
109            .collect();
110
111        assert_eq!(kv_map.get("I64").unwrap(), &Value::I64(64));
112        assert_eq!(kv_map.get("F64").unwrap(), &Value::F64(64.0));
113        assert_eq!(
114            kv_map.get("String").unwrap(),
115            &Value::String("I AM A STRING".into())
116        );
117        assert_eq!(kv_map.get("Bool").unwrap(), &Value::Bool(true));
118    }
119
120    #[test]
121    fn kv_to_attr() {
122        let kvs: Vec<KeyValue> = vec![
123            KeyValue::new("Bool", Value::Bool(true)),
124            KeyValue::new("String", Value::String("I AM A STRING".into())),
125            KeyValue::new("I64", Value::I64(64)),
126            KeyValue::new("F64", Value::F64(64.0)),
127        ];
128
129        let attrs = option_attr_from_kv(&kvs).unwrap();
130        assert_eq!(attrs.get("Bool").unwrap(), &AttributeValue::Bool(true));
131        assert_eq!(
132            attrs.get("String").unwrap(),
133            &AttributeValue::String("I AM A STRING".into())
134        );
135        assert_eq!(attrs.get("I64").unwrap(), &AttributeValue::I64(64));
136        assert_eq!(attrs.get("F64").unwrap(), &AttributeValue::F64(64.0));
137    }
138}