aws_smithy_observability_otel/
attributes.rs1use 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 AttributeValue::String("UNSUPPORTED ATTRIBUTE VALUE TYPE".into())
83 }
84 },
85 )
86 });
87
88 AttributesWrap(attrs)
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use std::collections::HashMap;
95
96 use super::*;
97 use aws_smithy_observability::{AttributeValue, Attributes};
98 use opentelemetry::Value;
99
100 #[test]
101 fn attr_to_kv() {
102 let mut attrs = Attributes::new();
103 attrs.set("I64", AttributeValue::I64(64));
104 attrs.set("F64", AttributeValue::F64(64.0));
105 attrs.set("String", AttributeValue::String("I AM A STRING".into()));
106 attrs.set("Bool", AttributeValue::Bool(true));
107
108 let kv = kv_from_option_attr(Some(&attrs));
109
110 let kv_map: HashMap<String, Value> = kv
111 .into_iter()
112 .map(|kv| (kv.key.to_string(), kv.value))
113 .collect();
114
115 assert_eq!(kv_map.get("I64").unwrap(), &Value::I64(64));
116 assert_eq!(kv_map.get("F64").unwrap(), &Value::F64(64.0));
117 assert_eq!(
118 kv_map.get("String").unwrap(),
119 &Value::String("I AM A STRING".into())
120 );
121 assert_eq!(kv_map.get("Bool").unwrap(), &Value::Bool(true));
122 }
123
124 #[test]
125 fn kv_to_attr() {
126 let kvs: Vec<KeyValue> = vec![
127 KeyValue::new("Bool", Value::Bool(true)),
128 KeyValue::new("String", Value::String("I AM A STRING".into())),
129 KeyValue::new("I64", Value::I64(64)),
130 KeyValue::new("F64", Value::F64(64.0)),
131 ];
132
133 let attrs = option_attr_from_kv(&kvs).unwrap();
134 assert_eq!(attrs.get("Bool").unwrap(), &AttributeValue::Bool(true));
135 assert_eq!(
136 attrs.get("String").unwrap(),
137 &AttributeValue::String("I AM A STRING".into())
138 );
139 assert_eq!(attrs.get("I64").unwrap(), &AttributeValue::I64(64));
140 assert_eq!(attrs.get("F64").unwrap(), &AttributeValue::F64(64.0));
141 }
142}