1pub mod trace_utils;
5pub mod v05;
6
7use libdd_tinybytes::{Bytes, BytesString};
8use serde::ser::SerializeStruct;
9use serde::Serialize;
10use std::borrow::Borrow;
11use std::collections::HashMap;
12use std::fmt;
13use std::hash::Hash;
14use std::str::FromStr;
15use v05::dict::SharedDict;
16
17use crate::tracer_payload::TraceChunks;
18
19#[derive(Debug, PartialEq)]
20pub enum SpanKey {
21 Service,
22 Name,
23 Resource,
24 TraceId,
25 SpanId,
26 ParentId,
27 Start,
28 Duration,
29 Error,
30 Meta,
31 Metrics,
32 Type,
33 MetaStruct,
34 SpanLinks,
35 SpanEvents,
36}
37
38impl FromStr for SpanKey {
39 type Err = SpanKeyParseError;
40
41 fn from_str(s: &str) -> Result<Self, Self::Err> {
42 match s {
43 "service" => Ok(SpanKey::Service),
44 "name" => Ok(SpanKey::Name),
45 "resource" => Ok(SpanKey::Resource),
46 "trace_id" => Ok(SpanKey::TraceId),
47 "span_id" => Ok(SpanKey::SpanId),
48 "parent_id" => Ok(SpanKey::ParentId),
49 "start" => Ok(SpanKey::Start),
50 "duration" => Ok(SpanKey::Duration),
51 "error" => Ok(SpanKey::Error),
52 "meta" => Ok(SpanKey::Meta),
53 "metrics" => Ok(SpanKey::Metrics),
54 "type" => Ok(SpanKey::Type),
55 "meta_struct" => Ok(SpanKey::MetaStruct),
56 "span_links" => Ok(SpanKey::SpanLinks),
57 "span_events" => Ok(SpanKey::SpanEvents),
58 _ => Err(SpanKeyParseError::new(format!("Invalid span key: {s}"))),
59 }
60 }
61}
62
63pub trait SpanText: Eq + Hash + Borrow<str> + Serialize + Default {
67 fn from_static_str(value: &'static str) -> Self;
68}
69
70impl SpanText for &str {
71 fn from_static_str(value: &'static str) -> Self {
72 value
73 }
74}
75
76impl SpanText for BytesString {
77 fn from_static_str(value: &'static str) -> Self {
78 BytesString::from_static(value)
79 }
80}
81
82fn is_empty_str<T: Borrow<str>>(value: &T) -> bool {
85 value.borrow().is_empty()
86}
87
88#[derive(Clone, Debug, Default, PartialEq, Serialize)]
100pub struct Span<T>
101where
102 T: SpanText,
103{
104 pub service: T,
105 pub name: T,
106 pub resource: T,
107 #[serde(skip_serializing_if = "is_empty_str")]
108 pub r#type: T,
109 #[serde(serialize_with = "serialize_lower_64_bits")]
110 pub trace_id: u128,
111 pub span_id: u64,
112 #[serde(skip_serializing_if = "is_default")]
113 pub parent_id: u64,
114 pub start: i64,
115 pub duration: i64,
116 #[serde(skip_serializing_if = "is_default")]
117 pub error: i32,
118 #[serde(skip_serializing_if = "HashMap::is_empty")]
119 pub meta: HashMap<T, T>,
120 #[serde(skip_serializing_if = "HashMap::is_empty")]
121 pub metrics: HashMap<T, f64>,
122 #[serde(skip_serializing_if = "HashMap::is_empty")]
125 pub meta_struct: HashMap<T, Bytes>,
126 #[serde(skip_serializing_if = "Vec::is_empty")]
127 pub span_links: Vec<SpanLink<T>>,
128 #[serde(skip_serializing_if = "Vec::is_empty")]
129 pub span_events: Vec<SpanEvent<T>>,
130}
131
132fn serialize_lower_64_bits<S>(v: &u128, serializer: S) -> Result<S::Ok, S::Error>
133where
134 S: serde::Serializer,
135{
136 serializer.serialize_u64(*v as u64)
137}
138
139#[derive(Clone, Debug, Default, PartialEq, Serialize)]
142pub struct SpanLink<T>
143where
144 T: SpanText,
145{
146 pub trace_id: u64,
147 pub trace_id_high: u64,
148 pub span_id: u64,
149 #[serde(skip_serializing_if = "HashMap::is_empty")]
150 pub attributes: HashMap<T, T>,
151 #[serde(skip_serializing_if = "is_empty_str")]
152 pub tracestate: T,
153 #[serde(skip_serializing_if = "is_default")]
154 pub flags: u32,
155}
156
157#[derive(Clone, Debug, Default, PartialEq, Serialize)]
160pub struct SpanEvent<T>
161where
162 T: SpanText,
163{
164 pub time_unix_nano: u64,
165 pub name: T,
166 #[serde(skip_serializing_if = "HashMap::is_empty")]
167 pub attributes: HashMap<T, AttributeAnyValue<T>>,
168}
169
170#[derive(Clone, Debug, PartialEq)]
171pub enum AttributeAnyValue<T>
172where
173 T: SpanText,
174{
175 SingleValue(AttributeArrayValue<T>),
176 Array(Vec<AttributeArrayValue<T>>),
177}
178
179#[derive(Serialize)]
180struct ArrayValueWrapper<'a, T: SpanText> {
181 values: &'a Vec<AttributeArrayValue<T>>,
182}
183
184impl<T> Serialize for AttributeAnyValue<T>
185where
186 T: SpanText,
187{
188 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
189 where
190 S: serde::Serializer,
191 {
192 let mut state = serializer.serialize_struct("AttributeAnyValue", 2)?;
193
194 match self {
195 AttributeAnyValue::SingleValue(attribute) => {
196 serialize_attribute_array::<S, T>(&mut state, attribute)?;
197 }
198 AttributeAnyValue::Array(value) => {
199 let value_type: u8 = self.into();
200 state.serialize_field("type", &value_type)?;
201 let wrapped_value = ArrayValueWrapper { values: value };
202 state.serialize_field("array_value", &wrapped_value)?;
203 }
204 }
205
206 state.end()
207 }
208}
209
210impl<T> From<&AttributeAnyValue<T>> for u8
211where
212 T: SpanText,
213{
214 fn from(attribute: &AttributeAnyValue<T>) -> u8 {
215 match attribute {
216 AttributeAnyValue::SingleValue(value) => value.into(),
217 AttributeAnyValue::Array(_) => 4,
218 }
219 }
220}
221
222#[derive(Clone, Debug, PartialEq)]
223pub enum AttributeArrayValue<T>
224where
225 T: SpanText,
226{
227 String(T),
228 Boolean(bool),
229 Integer(i64),
230 Double(f64),
231}
232
233impl<T> Serialize for AttributeArrayValue<T>
234where
235 T: SpanText,
236{
237 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
238 where
239 S: serde::Serializer,
240 {
241 let mut state = serializer.serialize_struct("AttributeArrayValue", 2)?;
242 serialize_attribute_array::<S, T>(&mut state, self)?;
243 state.end()
244 }
245}
246
247fn serialize_attribute_array<S, T>(
248 state: &mut S::SerializeStruct,
249 attribute: &AttributeArrayValue<T>,
250) -> Result<(), <S>::Error>
251where
252 T: SpanText,
253 S: serde::Serializer,
254{
255 let attribute_type: u8 = attribute.into();
256 state.serialize_field("type", &attribute_type)?;
257 match attribute {
258 AttributeArrayValue::String(value) => state.serialize_field("string_value", value),
259 AttributeArrayValue::Boolean(value) => state.serialize_field("bool_value", value),
260 AttributeArrayValue::Integer(value) => state.serialize_field("int_value", value),
261 AttributeArrayValue::Double(value) => state.serialize_field("double_value", value),
262 }
263}
264
265impl<T> From<&AttributeArrayValue<T>> for u8
266where
267 T: SpanText,
268{
269 fn from(attribute: &AttributeArrayValue<T>) -> u8 {
270 match attribute {
271 AttributeArrayValue::String(_) => 0,
272 AttributeArrayValue::Boolean(_) => 1,
273 AttributeArrayValue::Integer(_) => 2,
274 AttributeArrayValue::Double(_) => 3,
275 }
276 }
277}
278
279pub type SpanBytes = Span<BytesString>;
280pub type SpanLinkBytes = SpanLink<BytesString>;
281pub type SpanEventBytes = SpanEvent<BytesString>;
282pub type AttributeAnyValueBytes = AttributeAnyValue<BytesString>;
283pub type AttributeArrayValueBytes = AttributeArrayValue<BytesString>;
284
285pub type SpanSlice<'a> = Span<&'a str>;
286pub type SpanLinkSlice<'a> = SpanLink<&'a str>;
287pub type SpanEventSlice<'a> = SpanEvent<&'a str>;
288pub type AttributeAnyValueSlice<'a> = AttributeAnyValue<&'a str>;
289pub type AttributeArrayValueSlice<'a> = AttributeArrayValue<&'a str>;
290
291pub type TraceChunksBytes = TraceChunks<BytesString>;
292
293pub type SharedDictBytes = SharedDict<BytesString>;
294
295impl SpanSlice<'_> {
296 pub fn try_to_bytes(&self, bytes: &Bytes) -> Option<SpanBytes> {
300 Some(SpanBytes {
301 service: BytesString::try_from_bytes_slice(bytes, self.service)?,
302 name: BytesString::try_from_bytes_slice(bytes, self.name)?,
303 resource: BytesString::try_from_bytes_slice(bytes, self.resource)?,
304 r#type: BytesString::try_from_bytes_slice(bytes, self.r#type)?,
305 trace_id: self.trace_id,
306 span_id: self.span_id,
307 parent_id: self.parent_id,
308 start: self.start,
309 duration: self.duration,
310 error: self.error,
311 meta: self
312 .meta
313 .iter()
314 .map(|(k, v)| {
315 Some((
316 BytesString::try_from_bytes_slice(bytes, k)?,
317 BytesString::try_from_bytes_slice(bytes, v)?,
318 ))
319 })
320 .collect::<Option<HashMap<BytesString, BytesString>>>()?,
321 metrics: self
322 .metrics
323 .iter()
324 .map(|(k, v)| Some((BytesString::try_from_bytes_slice(bytes, k)?, *v)))
325 .collect::<Option<HashMap<BytesString, f64>>>()?,
326 meta_struct: self
327 .meta_struct
328 .iter()
329 .map(|(k, v)| Some((BytesString::try_from_bytes_slice(bytes, k)?, v.clone())))
330 .collect::<Option<HashMap<BytesString, Bytes>>>()?,
331 span_links: self
332 .span_links
333 .iter()
334 .map(|link| link.try_to_bytes(bytes))
335 .collect::<Option<Vec<SpanLinkBytes>>>()?,
336 span_events: self
337 .span_events
338 .iter()
339 .map(|event| event.try_to_bytes(bytes))
340 .collect::<Option<Vec<SpanEventBytes>>>()?,
341 })
342 }
343}
344
345impl SpanLinkSlice<'_> {
346 pub fn try_to_bytes(&self, bytes: &Bytes) -> Option<SpanLinkBytes> {
350 Some(SpanLinkBytes {
351 trace_id: self.trace_id,
352 trace_id_high: self.trace_id_high,
353 span_id: self.span_id,
354 attributes: self
355 .attributes
356 .iter()
357 .map(|(k, v)| {
358 Some((
359 BytesString::try_from_bytes_slice(bytes, k)?,
360 BytesString::try_from_bytes_slice(bytes, v)?,
361 ))
362 })
363 .collect::<Option<HashMap<BytesString, BytesString>>>()?,
364 tracestate: BytesString::try_from_bytes_slice(bytes, self.tracestate)?,
365 flags: self.flags,
366 })
367 }
368}
369
370impl SpanEventSlice<'_> {
371 pub fn try_to_bytes(&self, bytes: &Bytes) -> Option<SpanEventBytes> {
375 Some(SpanEventBytes {
376 time_unix_nano: self.time_unix_nano,
377 name: BytesString::try_from_bytes_slice(bytes, self.name)?,
378 attributes: self
379 .attributes
380 .iter()
381 .map(|(k, v)| {
382 Some((
383 BytesString::try_from_bytes_slice(bytes, k)?,
384 v.try_to_bytes(bytes)?,
385 ))
386 })
387 .collect::<Option<HashMap<BytesString, AttributeAnyValueBytes>>>()?,
388 })
389 }
390}
391
392impl AttributeAnyValueSlice<'_> {
393 pub fn try_to_bytes(&self, bytes: &Bytes) -> Option<AttributeAnyValueBytes> {
397 match self {
398 AttributeAnyValue::SingleValue(value) => {
399 Some(AttributeAnyValue::SingleValue(value.try_to_bytes(bytes)?))
400 }
401 AttributeAnyValue::Array(value) => Some(AttributeAnyValue::Array(
402 value
403 .iter()
404 .map(|attribute| attribute.try_to_bytes(bytes))
405 .collect::<Option<Vec<AttributeArrayValueBytes>>>()?,
406 )),
407 }
408 }
409}
410
411impl AttributeArrayValueSlice<'_> {
412 pub fn try_to_bytes(&self, bytes: &Bytes) -> Option<AttributeArrayValueBytes> {
416 match self {
417 AttributeArrayValue::String(value) => Some(AttributeArrayValue::String(
418 BytesString::try_from_bytes_slice(bytes, value)?,
419 )),
420 AttributeArrayValue::Boolean(value) => Some(AttributeArrayValue::Boolean(*value)),
421 AttributeArrayValue::Integer(value) => Some(AttributeArrayValue::Integer(*value)),
422 AttributeArrayValue::Double(value) => Some(AttributeArrayValue::Double(*value)),
423 }
424 }
425}
426
427#[derive(Debug)]
428pub struct SpanKeyParseError {
429 pub message: String,
430}
431
432impl SpanKeyParseError {
433 pub fn new(message: impl Into<String>) -> Self {
434 SpanKeyParseError {
435 message: message.into(),
436 }
437 }
438}
439impl fmt::Display for SpanKeyParseError {
440 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441 write!(f, "SpanKeyParseError: {}", self.message)
442 }
443}
444impl std::error::Error for SpanKeyParseError {}
445
446fn is_default<T: Default + PartialEq>(t: &T) -> bool {
447 t == &T::default()
448}
449
450#[cfg(test)]
451mod tests {
452 use super::{AttributeAnyValue, AttributeArrayValue, Span, SpanEvent, SpanLink};
453 use crate::msgpack_decoder::v04::span::decode_span;
454 use std::collections::HashMap;
455
456 #[test]
457 fn skip_serializing_empty_fields_test() {
458 let expected = b"\x87\xa7service\xa0\xa4name\xa0\xa8resource\xa0\xa8trace_id\x00\xa7span_id\x00\xa5start\x00\xa8duration\x00";
459 let val: Span<&str> = Span::default();
460 let serialized = rmp_serde::encode::to_vec_named(&val).unwrap();
461 assert_eq!(expected, serialized.as_slice());
462 }
463
464 #[test]
465 fn serialize_deserialize_test() {
466 let span: Span<&str> = Span {
467 name: "tracing.operation",
468 resource: "MyEndpoint",
469 span_links: vec![SpanLink {
470 trace_id: 42,
471 attributes: HashMap::from([("span", "link")]),
472 tracestate: "running",
473 ..Default::default()
474 }],
475 span_events: vec![SpanEvent {
476 time_unix_nano: 1727211691770716000,
477 name: "exception",
478 attributes: HashMap::from([
479 (
480 "exception.message",
481 AttributeAnyValue::SingleValue(AttributeArrayValue::String(
482 "Cannot divide by zero",
483 )),
484 ),
485 (
486 "exception.type",
487 AttributeAnyValue::SingleValue(AttributeArrayValue::String("RuntimeError")),
488 ),
489 (
490 "exception.escaped",
491 AttributeAnyValue::SingleValue(AttributeArrayValue::Boolean(false)),
492 ),
493 (
494 "exception.count",
495 AttributeAnyValue::SingleValue(AttributeArrayValue::Integer(1)),
496 ),
497 (
498 "exception.lines",
499 AttributeAnyValue::Array(vec![
500 AttributeArrayValue::String(" File \"<string>\", line 1, in <module>"),
501 AttributeArrayValue::String(" File \"<string>\", line 1, in divide"),
502 AttributeArrayValue::String("RuntimeError: Cannot divide by zero"),
503 ]),
504 ),
505 ]),
506 }],
507 ..Default::default()
508 };
509
510 let serialized = rmp_serde::encode::to_vec_named(&span).unwrap();
511 let mut serialized_slice = serialized.as_ref();
512 let deserialized = decode_span(&mut serialized_slice).unwrap();
513
514 assert_eq!(span.name, deserialized.name);
515 assert_eq!(span.resource, deserialized.resource);
516 assert_eq!(
517 span.span_links[0].trace_id,
518 deserialized.span_links[0].trace_id
519 );
520 assert_eq!(
521 span.span_links[0].tracestate,
522 deserialized.span_links[0].tracestate
523 );
524 assert_eq!(span.span_events[0].name, deserialized.span_events[0].name);
525 assert_eq!(
526 span.span_events[0].time_unix_nano,
527 deserialized.span_events[0].time_unix_nano
528 );
529 for attribut in &deserialized.span_events[0].attributes {
530 assert!(span.span_events[0].attributes.contains_key(attribut.0))
531 }
532 }
533
534 #[test]
535 fn serialize_event_test() {
536 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";
539
540 let span: Span<&str> = Span {
541 span_events: vec![SpanEvent {
542 time_unix_nano: 1727211691770716000,
543 name: "test",
544 attributes: HashMap::from([(
545 "test.event",
546 AttributeAnyValue::SingleValue(AttributeArrayValue::Double(4.2)),
547 )]),
548 }],
549 ..Default::default()
550 };
551
552 let serialized = rmp_serde::encode::to_vec_named(&span).unwrap();
553 assert_eq!(expected, serialized.as_slice());
554 }
555}