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