1use crate::span::{BytesData, SliceData, SpanKeyParseError, TraceData};
5use crate::tracer_payload::TraceChunks;
6use serde::ser::SerializeStruct;
7use serde::Serialize;
8use std::borrow::Borrow;
9use std::collections::HashMap;
10use std::str::FromStr;
11
12#[derive(Debug, PartialEq)]
13pub enum SpanKey {
14 Service,
15 Name,
16 Resource,
17 TraceId,
18 SpanId,
19 ParentId,
20 Start,
21 Duration,
22 Error,
23 Meta,
24 Metrics,
25 Type,
26 MetaStruct,
27 SpanLinks,
28 SpanEvents,
29}
30
31impl FromStr for SpanKey {
32 type Err = SpanKeyParseError;
33
34 fn from_str(s: &str) -> Result<Self, Self::Err> {
35 match s {
36 "service" => Ok(SpanKey::Service),
37 "name" => Ok(SpanKey::Name),
38 "resource" => Ok(SpanKey::Resource),
39 "trace_id" => Ok(SpanKey::TraceId),
40 "span_id" => Ok(SpanKey::SpanId),
41 "parent_id" => Ok(SpanKey::ParentId),
42 "start" => Ok(SpanKey::Start),
43 "duration" => Ok(SpanKey::Duration),
44 "error" => Ok(SpanKey::Error),
45 "meta" => Ok(SpanKey::Meta),
46 "metrics" => Ok(SpanKey::Metrics),
47 "type" => Ok(SpanKey::Type),
48 "meta_struct" => Ok(SpanKey::MetaStruct),
49 "span_links" => Ok(SpanKey::SpanLinks),
50 "span_events" => Ok(SpanKey::SpanEvents),
51 _ => Err(SpanKeyParseError::new(format!("Invalid span key: {s}"))),
52 }
53 }
54}
55
56fn is_empty_str<T: Borrow<str>>(value: &T) -> bool {
59 value.borrow().is_empty()
60}
61
62#[derive(Debug, Default, PartialEq, Serialize)]
74pub struct Span<T: TraceData> {
75 pub service: T::Text,
76 pub name: T::Text,
77 pub resource: T::Text,
78 #[serde(skip_serializing_if = "is_empty_str")]
79 pub r#type: T::Text,
80 #[serde(serialize_with = "serialize_lower_64_bits")]
81 pub trace_id: u128,
82 pub span_id: u64,
83 #[serde(skip_serializing_if = "is_default")]
84 pub parent_id: u64,
85 pub start: i64,
86 pub duration: i64,
87 #[serde(skip_serializing_if = "is_default")]
88 pub error: i32,
89 #[serde(skip_serializing_if = "HashMap::is_empty")]
90 pub meta: HashMap<T::Text, T::Text>,
91 #[serde(skip_serializing_if = "HashMap::is_empty")]
92 pub metrics: HashMap<T::Text, f64>,
93 #[serde(skip_serializing_if = "HashMap::is_empty")]
94 pub meta_struct: HashMap<T::Text, T::Bytes>,
95 #[serde(skip_serializing_if = "Vec::is_empty")]
96 pub span_links: Vec<SpanLink<T>>,
97 #[serde(skip_serializing_if = "Vec::is_empty")]
98 pub span_events: Vec<SpanEvent<T>>,
99}
100
101impl<T: TraceData> Clone for Span<T>
102where
103 T::Text: Clone,
104 T::Bytes: Clone,
105{
106 fn clone(&self) -> Self {
107 Span {
108 service: self.service.clone(),
109 name: self.name.clone(),
110 resource: self.resource.clone(),
111 r#type: self.r#type.clone(),
112 trace_id: self.trace_id,
113 span_id: self.span_id,
114 parent_id: self.parent_id,
115 start: self.start,
116 duration: self.duration,
117 error: self.error,
118 meta: self.meta.clone(),
119 metrics: self.metrics.clone(),
120 meta_struct: self.meta_struct.clone(),
121 span_links: self.span_links.clone(),
122 span_events: self.span_events.clone(),
123 }
124 }
125}
126
127fn serialize_lower_64_bits<S>(v: &u128, serializer: S) -> Result<S::Ok, S::Error>
128where
129 S: serde::Serializer,
130{
131 serializer.serialize_u64(*v as u64)
132}
133
134#[derive(Debug, Default, PartialEq, Serialize)]
137pub struct SpanLink<T: TraceData> {
138 pub trace_id: u64,
139 pub trace_id_high: u64,
140 pub span_id: u64,
141 #[serde(skip_serializing_if = "HashMap::is_empty")]
142 pub attributes: HashMap<T::Text, T::Text>,
143 #[serde(skip_serializing_if = "is_empty_str")]
144 pub tracestate: T::Text,
145 #[serde(skip_serializing_if = "is_default")]
146 pub flags: u32,
147}
148
149impl<T: TraceData> Clone for SpanLink<T>
150where
151 T::Text: Clone,
152{
153 fn clone(&self) -> Self {
154 SpanLink {
155 trace_id: self.trace_id,
156 trace_id_high: self.trace_id_high,
157 span_id: self.span_id,
158 attributes: self.attributes.clone(),
159 tracestate: self.tracestate.clone(),
160 flags: self.flags,
161 }
162 }
163}
164
165#[derive(Debug, Default, PartialEq, Serialize)]
168pub struct SpanEvent<T: TraceData> {
169 pub time_unix_nano: u64,
170 pub name: T::Text,
171 #[serde(skip_serializing_if = "HashMap::is_empty")]
172 pub attributes: HashMap<T::Text, AttributeAnyValue<T>>,
173}
174
175impl<T: TraceData> Clone for SpanEvent<T>
176where
177 T::Text: Clone,
178{
179 fn clone(&self) -> Self {
180 SpanEvent {
181 time_unix_nano: self.time_unix_nano,
182 name: self.name.clone(),
183 attributes: self.attributes.clone(),
184 }
185 }
186}
187
188#[derive(Debug, PartialEq)]
189pub enum AttributeAnyValue<T: TraceData> {
190 SingleValue(AttributeArrayValue<T>),
191 Array(Vec<AttributeArrayValue<T>>),
192}
193
194#[derive(Serialize)]
195struct ArrayValueWrapper<'a, T: TraceData> {
196 #[serde(bound(serialize = "T::Text: Serialize"))]
197 values: &'a Vec<AttributeArrayValue<T>>,
198}
199
200impl<T: TraceData> Serialize for AttributeAnyValue<T> {
201 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
202 where
203 S: serde::Serializer,
204 {
205 let mut state = serializer.serialize_struct("AttributeAnyValue", 2)?;
206
207 match self {
208 AttributeAnyValue::SingleValue(attribute) => {
209 serialize_attribute_array::<S, T>(&mut state, attribute)?;
210 }
211 AttributeAnyValue::Array(value) => {
212 let value_type: u8 = self.into();
213 state.serialize_field("type", &value_type)?;
214 let wrapped_value = ArrayValueWrapper { values: value };
215 state.serialize_field("array_value", &wrapped_value)?;
216 }
217 }
218
219 state.end()
220 }
221}
222
223impl<T: TraceData> From<&AttributeAnyValue<T>> for u8 {
224 fn from(attribute: &AttributeAnyValue<T>) -> u8 {
225 match attribute {
226 AttributeAnyValue::SingleValue(value) => value.into(),
227 AttributeAnyValue::Array(_) => 4,
228 }
229 }
230}
231
232impl<T: TraceData> Clone for AttributeAnyValue<T>
233where
234 T::Text: Clone,
235{
236 fn clone(&self) -> Self {
237 match self {
238 AttributeAnyValue::SingleValue(v) => AttributeAnyValue::SingleValue(v.clone()),
239 AttributeAnyValue::Array(vec) => AttributeAnyValue::Array(vec.clone()),
240 }
241 }
242}
243
244#[derive(Debug, PartialEq)]
245pub enum AttributeArrayValue<T: TraceData> {
246 String(T::Text),
247 Boolean(bool),
248 Integer(i64),
249 Double(f64),
250}
251
252impl<T: TraceData> Clone for AttributeArrayValue<T>
253where
254 T::Text: Clone,
255{
256 fn clone(&self) -> Self {
257 match self {
258 AttributeArrayValue::String(v) => AttributeArrayValue::String(v.clone()),
259 AttributeArrayValue::Boolean(v) => AttributeArrayValue::Boolean(*v),
260 AttributeArrayValue::Integer(v) => AttributeArrayValue::Integer(*v),
261 AttributeArrayValue::Double(v) => AttributeArrayValue::Double(*v),
262 }
263 }
264}
265
266impl<T: TraceData> Serialize for AttributeArrayValue<T> {
267 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
268 where
269 S: serde::Serializer,
270 {
271 let mut state = serializer.serialize_struct("AttributeArrayValue", 2)?;
272 serialize_attribute_array::<S, T>(&mut state, self)?;
273 state.end()
274 }
275}
276
277fn serialize_attribute_array<S, T>(
278 state: &mut S::SerializeStruct,
279 attribute: &AttributeArrayValue<T>,
280) -> Result<(), <S>::Error>
281where
282 T: TraceData,
283 S: serde::Serializer,
284{
285 let attribute_type: u8 = attribute.into();
286 state.serialize_field("type", &attribute_type)?;
287 match attribute {
288 AttributeArrayValue::String(value) => state.serialize_field("string_value", value),
289 AttributeArrayValue::Boolean(value) => state.serialize_field("bool_value", value),
290 AttributeArrayValue::Integer(value) => state.serialize_field("int_value", value),
291 AttributeArrayValue::Double(value) => state.serialize_field("double_value", value),
292 }
293}
294
295impl<T: TraceData> From<&AttributeArrayValue<T>> for u8 {
296 fn from(attribute: &AttributeArrayValue<T>) -> u8 {
297 match attribute {
298 AttributeArrayValue::String(_) => 0,
299 AttributeArrayValue::Boolean(_) => 1,
300 AttributeArrayValue::Integer(_) => 2,
301 AttributeArrayValue::Double(_) => 3,
302 }
303 }
304}
305
306fn is_default<T: Default + PartialEq>(t: &T) -> bool {
307 t == &T::default()
308}
309
310pub type SpanBytes = Span<BytesData>;
311pub type SpanLinkBytes = SpanLink<BytesData>;
312pub type SpanEventBytes = SpanEvent<BytesData>;
313pub type AttributeAnyValueBytes = AttributeAnyValue<BytesData>;
314pub type AttributeArrayValueBytes = AttributeArrayValue<BytesData>;
315
316pub type SpanSlice<'a> = Span<SliceData<'a>>;
317pub type SpanLinkSlice<'a> = SpanLink<SliceData<'a>>;
318pub type SpanEventSlice<'a> = SpanEvent<SliceData<'a>>;
319pub type AttributeAnyValueSlice<'a> = AttributeAnyValue<SliceData<'a>>;
320pub type AttributeArrayValueSlice<'a> = AttributeArrayValue<SliceData<'a>>;
321
322pub type TraceChunksBytes = TraceChunks<BytesData>;
323
324#[cfg(test)]
325mod tests {
326 use super::{AttributeAnyValue, AttributeArrayValue, Span, SpanEvent, SpanLink};
327 use crate::msgpack_decoder::decode::buffer::Buffer;
328 use crate::msgpack_decoder::v04::span::decode_span;
329 use crate::span::SliceData;
330 use std::collections::HashMap;
331
332 #[test]
333 fn skip_serializing_empty_fields_test() {
334 let expected = b"\x87\xa7service\xa0\xa4name\xa0\xa8resource\xa0\xa8trace_id\x00\xa7span_id\x00\xa5start\x00\xa8duration\x00";
335 let val: Span<SliceData<'_>> = Span::default();
336 let serialized = rmp_serde::encode::to_vec_named(&val).unwrap();
337 assert_eq!(expected, serialized.as_slice());
338 }
339
340 #[test]
341 fn serialize_deserialize_test() {
342 let span: Span<SliceData<'_>> = Span {
343 name: "tracing.operation",
344 resource: "MyEndpoint",
345 span_links: vec![SpanLink {
346 trace_id: 42,
347 attributes: HashMap::from([("span", "link")]),
348 tracestate: "running",
349 ..Default::default()
350 }],
351 span_events: vec![SpanEvent {
352 time_unix_nano: 1727211691770716000,
353 name: "exception",
354 attributes: HashMap::from([
355 (
356 "exception.message",
357 AttributeAnyValue::SingleValue(AttributeArrayValue::String(
358 "Cannot divide by zero",
359 )),
360 ),
361 (
362 "exception.type",
363 AttributeAnyValue::SingleValue(AttributeArrayValue::String("RuntimeError")),
364 ),
365 (
366 "exception.escaped",
367 AttributeAnyValue::SingleValue(AttributeArrayValue::Boolean(false)),
368 ),
369 (
370 "exception.count",
371 AttributeAnyValue::SingleValue(AttributeArrayValue::Integer(1)),
372 ),
373 (
374 "exception.lines",
375 AttributeAnyValue::Array(vec![
376 AttributeArrayValue::String(" File \"<string>\", line 1, in <module>"),
377 AttributeArrayValue::String(" File \"<string>\", line 1, in divide"),
378 AttributeArrayValue::String("RuntimeError: Cannot divide by zero"),
379 ]),
380 ),
381 ]),
382 }],
383 ..Default::default()
384 };
385
386 let serialized = rmp_serde::encode::to_vec_named(&span).unwrap();
387 let mut serialized_slice = Buffer::<SliceData<'_>>::new(serialized.as_ref());
388 let deserialized = decode_span(&mut serialized_slice).unwrap();
389
390 assert_eq!(span.name, deserialized.name);
391 assert_eq!(span.resource, deserialized.resource);
392 assert_eq!(
393 span.span_links[0].trace_id,
394 deserialized.span_links[0].trace_id
395 );
396 assert_eq!(
397 span.span_links[0].tracestate,
398 deserialized.span_links[0].tracestate
399 );
400 assert_eq!(span.span_events[0].name, deserialized.span_events[0].name);
401 assert_eq!(
402 span.span_events[0].time_unix_nano,
403 deserialized.span_events[0].time_unix_nano
404 );
405 for attribut in &deserialized.span_events[0].attributes {
406 assert!(span.span_events[0].attributes.contains_key(attribut.0))
407 }
408 }
409
410 #[test]
411 fn serialize_event_test() {
412 let expected = b"\x88\xa7service\xa0\xa4name\xa0\xa8resource\xa0\xa8trace_id\x00\xa7span_id\x00\xa5start\x00\xa8duration\x00\xabspan_events\x91\x83\xaetime_unix_nano\xcf\x17\xf8I\xe1\xeb\xe5\x1f`\xa4name\xa4test\xaaattributes\x81\xaatest.event\x82\xa4type\x03\xacdouble_value\xcb@\x10\xcc\xcc\xcc\xcc\xcc\xcd";
415
416 let span: Span<SliceData<'_>> = Span {
417 span_events: vec![SpanEvent {
418 time_unix_nano: 1727211691770716000,
419 name: "test",
420 attributes: HashMap::from([(
421 "test.event",
422 AttributeAnyValue::SingleValue(AttributeArrayValue::Double(4.2)),
423 )]),
424 }],
425 ..Default::default()
426 };
427
428 let serialized = rmp_serde::encode::to_vec_named(&span).unwrap();
429 assert_eq!(expected, serialized.as_slice());
430 }
431}