1pub mod dict;
5
6use crate::span::v04::{AttributeAnyValue, AttributeArrayValue, SpanEvent, SpanLink};
7use crate::span::{SharedDictBytes, SpanText, TraceData, SPAN_LINK_FLAGS_SET_SENTINEL};
8use anyhow::Result;
9use indexmap::map::RawEntryApiV1;
10use libdd_tinybytes::BytesString;
11use serde::ser::{SerializeMap, SerializeSeq};
12use serde::{Serialize, Serializer};
13use std::borrow::Borrow;
14use std::collections::HashMap;
15
16#[derive(Clone, Debug, Default, PartialEq, Serialize)]
21pub struct Span {
22 pub service: u32,
23 pub name: u32,
24 pub resource: u32,
25 pub trace_id: u64,
26 pub span_id: u64,
27 pub parent_id: u64,
28 pub start: i64,
29 pub duration: i64,
30 pub error: i32,
31 pub meta: HashMap<u32, u32>,
32 pub metrics: HashMap<u32, f64>,
33 pub r#type: u32,
34}
35
36struct SpanLinksSerializerV05<'a, T: TraceData>(&'a [SpanLink<T>]);
48struct SpanLinkSerializerV05<'a, T: TraceData>(&'a SpanLink<T>);
49
50impl<'a, T: TraceData> Serialize for SpanLinksSerializerV05<'a, T> {
51 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
52 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
53 for link in self.0 {
54 seq.serialize_element(&SpanLinkSerializerV05::<T>(link))?;
55 }
56 seq.end()
57 }
58}
59
60impl<'a, T: TraceData> Serialize for SpanLinkSerializerV05<'a, T> {
61 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
62 let link = self.0;
63 let tracestate: &str = link.tracestate.borrow();
64 let has_tracestate = !tracestate.is_empty();
65 let has_attributes = !link.attributes.is_empty();
66 let has_flags = link.flags != 0;
67 let len = 2 + has_tracestate as usize + has_attributes as usize + has_flags as usize;
68 let mut map = serializer.serialize_map(Some(len))?;
69 map.serialize_entry(
70 "trace_id",
71 &format!("{:016x}{:016x}", link.trace_id_high, link.trace_id),
72 )?;
73 map.serialize_entry("span_id", &format!("{:016x}", link.span_id))?;
74 if has_tracestate {
75 map.serialize_entry("tracestate", &link.tracestate)?;
76 }
77 if has_attributes {
78 map.serialize_entry(
79 "attributes",
80 &SortedStrMapSerializerV05::<T>(&link.attributes),
81 )?;
82 }
83 if has_flags {
84 map.serialize_entry("flags", &(link.flags & !SPAN_LINK_FLAGS_SET_SENTINEL))?;
85 }
86 map.end()
87 }
88}
89
90struct SortedStrMapSerializerV05<'a, T: TraceData>(&'a HashMap<T::Text, T::Text>);
93
94impl<'a, T: TraceData> Serialize for SortedStrMapSerializerV05<'a, T> {
95 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
96 let mut entries: Vec<(&str, &T::Text)> =
97 self.0.iter().map(|(k, v)| (k.borrow(), v)).collect();
98 entries.sort_unstable_by_key(|(k, _)| *k);
99 let mut map = serializer.serialize_map(Some(entries.len()))?;
100 for (key, value) in entries {
101 map.serialize_entry(key, value)?;
102 }
103 map.end()
104 }
105}
106
107struct SpanEventsSerializerV05<'a, T: TraceData>(&'a [SpanEvent<T>]);
112struct SpanEventSerializerV05<'a, T: TraceData>(&'a SpanEvent<T>);
113struct SpanEventAttributesSerializerV05<'a, T: TraceData>(
114 &'a HashMap<T::Text, AttributeAnyValue<T>>,
115);
116struct AttributeAnyValueV05<'a, T: TraceData>(&'a AttributeAnyValue<T>);
117struct AttributeArrayValueV05<'a, T: TraceData>(&'a AttributeArrayValue<T>);
118
119impl<'a, T: TraceData> Serialize for SpanEventsSerializerV05<'a, T> {
120 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
121 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
122 for event in self.0 {
123 seq.serialize_element(&SpanEventSerializerV05::<T>(event))?;
124 }
125 seq.end()
126 }
127}
128
129impl<'a, T: TraceData> Serialize for SpanEventSerializerV05<'a, T> {
130 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
131 let event = self.0;
132 let mut map = serializer.serialize_map(Some(3))?;
133 map.serialize_entry("time_unix_nano", &event.time_unix_nano)?;
134 map.serialize_entry("name", &event.name)?;
135 map.serialize_entry(
136 "attributes",
137 &SpanEventAttributesSerializerV05::<T>(&event.attributes),
138 )?;
139 map.end()
140 }
141}
142
143impl<'a, T: TraceData> Serialize for SpanEventAttributesSerializerV05<'a, T> {
144 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
145 let mut entries: Vec<(&str, &AttributeAnyValue<T>)> =
148 self.0.iter().map(|(k, v)| (k.borrow(), v)).collect();
149 entries.sort_unstable_by_key(|(k, _)| *k);
150 let mut map = serializer.serialize_map(Some(entries.len()))?;
151 for (key, value) in entries {
152 map.serialize_entry(key, &AttributeAnyValueV05::<T>(value))?;
153 }
154 map.end()
155 }
156}
157
158impl<'a, T: TraceData> Serialize for AttributeAnyValueV05<'a, T> {
159 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
160 match self.0 {
161 AttributeAnyValue::SingleValue(value) => {
162 AttributeArrayValueV05::<T>(value).serialize(serializer)
163 }
164 AttributeAnyValue::Array(values) => {
165 let mut seq = serializer.serialize_seq(Some(values.len()))?;
166 for value in values {
167 seq.serialize_element(&AttributeArrayValueV05::<T>(value))?;
168 }
169 seq.end()
170 }
171 }
172 }
173}
174
175impl<'a, T: TraceData> Serialize for AttributeArrayValueV05<'a, T> {
176 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
177 match self.0 {
178 AttributeArrayValue::String(value) => value.serialize(serializer),
179 AttributeArrayValue::Boolean(value) => serializer.serialize_bool(*value),
180 AttributeArrayValue::Integer(value) => serializer.serialize_i64(*value),
181 AttributeArrayValue::Double(value) => serializer.serialize_f64(*value),
182 }
183 }
184}
185
186fn get_or_insert(
192 dict: &mut SharedDictBytes,
193 str: &impl SpanText,
194) -> Result<u32, std::num::TryFromIntError> {
195 let entry = dict.map.raw_entry_mut_v1().from_key(str.borrow());
196 let idx = entry.index();
197 entry.or_insert_with(|| (str.to_bytes_string(), ()));
198 idx.try_into()
199}
200
201pub fn from_v04_span<T: TraceData>(
220 span: crate::span::v04::Span<T>,
221 dict: &mut SharedDictBytes,
222) -> Result<Span> {
223 let meta_len = span.meta.len();
224 let metrics_len = span.metrics.len();
225
226 let serialized_span_links = if span.span_links.is_empty() {
229 None
230 } else {
231 Some(serde_json::to_string(&SpanLinksSerializerV05::<T>(
232 &span.span_links,
233 ))?)
234 };
235 let serialized_span_events = if span.span_events.is_empty() {
236 None
237 } else {
238 Some(serde_json::to_string(&SpanEventsSerializerV05::<T>(
239 &span.span_events,
240 ))?)
241 };
242
243 let extra_meta =
244 serialized_span_links.is_some() as usize + serialized_span_events.is_some() as usize;
245
246 let service = get_or_insert(dict, &span.service)?;
249 let name = get_or_insert(dict, &span.name)?;
250 let resource = get_or_insert(dict, &span.resource)?;
251 let mut meta = span.meta.into_iter().try_fold(
252 HashMap::with_capacity(meta_len + extra_meta),
253 |mut meta, (k, v)| -> anyhow::Result<HashMap<u32, u32>> {
254 meta.insert(get_or_insert(dict, &k)?, get_or_insert(dict, &v)?);
255 Ok(meta)
256 },
257 )?;
258
259 if let Some(links_json) = serialized_span_links {
260 let key = dict.get_or_insert(BytesString::from_static("_dd.span_links"))?;
261 let value = dict.get_or_insert(BytesString::from(links_json))?;
262 meta.insert(key, value);
263 }
264 if let Some(events_json) = serialized_span_events {
265 let key = dict.get_or_insert(BytesString::from_static("events"))?;
266 let value = dict.get_or_insert(BytesString::from(events_json))?;
267 meta.insert(key, value);
268 }
269
270 let metrics = span.metrics.into_iter().try_fold(
271 HashMap::with_capacity(metrics_len),
272 |mut metrics, (k, v)| -> anyhow::Result<HashMap<u32, f64>> {
273 metrics.insert(get_or_insert(dict, &k)?, v);
274 Ok(metrics)
275 },
276 )?;
277 let r#type = get_or_insert(dict, &span.r#type)?;
278
279 Ok(Span {
280 service,
281 name,
282 resource,
283 trace_id: span.trace_id as u64,
284 span_id: span.span_id,
285 parent_id: span.parent_id,
286 start: span.start,
287 duration: span.duration,
288 error: span.error,
289 meta,
290 metrics,
291 r#type,
292 })
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298 use crate::span::v04::{SpanBytes, VecMap};
299 use crate::span::BytesData;
300 use libdd_tinybytes::BytesString;
301
302 fn meta_json(dict: &SharedDictBytes, span: &Span, key: &str) -> Option<String> {
304 let entries: Vec<&str> = dict.iter().map(|s| s.as_str()).collect();
305 let key_idx = entries.iter().position(|s| *s == key)? as u32;
306 let val_idx = *span.meta.get(&key_idx)?;
307 Some(entries[val_idx as usize].to_string())
308 }
309
310 #[test]
311 fn from_span_bytes_test() {
312 let span = SpanBytes {
313 service: BytesString::from("service"),
314 name: BytesString::from("name"),
315 resource: BytesString::from("resource"),
316 r#type: BytesString::from("type"),
317 trace_id: 1,
318 span_id: 1,
319 parent_id: 0,
320 start: 1,
321 duration: 111,
322 error: 0,
323 meta: vec![(
324 BytesString::from("meta_field"),
325 BytesString::from("meta_value"),
326 )]
327 .into(),
328 metrics: vec![(BytesString::from("metrics_field"), 1.1)].into(),
329 meta_struct: VecMap::new(),
330 span_links: vec![],
331 span_events: vec![],
332 };
333
334 let mut dict = SharedDictBytes::default();
335 let v05_span = from_v04_span(span, &mut dict).unwrap();
336
337 let get_index_from_str = |str: &str| -> u32 {
338 dict.iter()
339 .position(|s| s.as_str() == str)
340 .unwrap()
341 .try_into()
342 .unwrap()
343 };
344
345 assert_eq!(v05_span.service, get_index_from_str("service"));
346 assert_eq!(v05_span.name, get_index_from_str("name"));
347 assert_eq!(v05_span.resource, get_index_from_str("resource"));
348 assert_eq!(v05_span.r#type, get_index_from_str("type"));
349 assert_eq!(v05_span.trace_id, 1);
350 assert_eq!(v05_span.span_id, 1);
351 assert_eq!(v05_span.parent_id, 0);
352 assert_eq!(v05_span.start, 1);
353 assert_eq!(v05_span.duration, 111);
354 assert_eq!(v05_span.error, 0);
355 assert_eq!(v05_span.meta.len(), 1);
356 assert_eq!(v05_span.metrics.len(), 1);
357
358 assert_eq!(
359 *v05_span
360 .meta
361 .get(&get_index_from_str("meta_field"))
362 .unwrap(),
363 get_index_from_str("meta_value")
364 );
365 assert_eq!(
366 *v05_span
367 .metrics
368 .get(&get_index_from_str("metrics_field"))
369 .unwrap(),
370 1.1
371 );
372 }
373
374 fn base_span() -> SpanBytes {
375 SpanBytes {
376 service: BytesString::from("service"),
377 name: BytesString::from("name"),
378 resource: BytesString::from("resource"),
379 r#type: BytesString::from("type"),
380 trace_id: 1,
381 span_id: 1,
382 parent_id: 0,
383 start: 1,
384 duration: 111,
385 error: 0,
386 meta: vec![(
387 BytesString::from("meta_field"),
388 BytesString::from("meta_value"),
389 )]
390 .into(),
391 metrics: VecMap::new(),
392 meta_struct: VecMap::new(),
393 span_links: vec![],
394 span_events: vec![],
395 }
396 }
397
398 #[test]
401 fn from_v04_span_serializes_links_and_events_test() {
402 let mut span = base_span();
403 span.span_links = vec![SpanLink::<BytesData> {
404 trace_id: 12345,
405 trace_id_high: 67890,
406 span_id: 54321,
407 attributes: HashMap::from([(BytesString::from("key"), BytesString::from("val"))]),
408 tracestate: BytesString::from("tracestate_value"),
409 flags: 1,
410 }];
411 span.span_events = vec![SpanEvent::<BytesData> {
412 time_unix_nano: 123,
413 name: BytesString::from("ev1"),
414 attributes: HashMap::from([(
415 BytesString::from("str_attr"),
416 AttributeAnyValue::SingleValue(AttributeArrayValue::String(BytesString::from(
417 "val",
418 ))),
419 )]),
420 }];
421
422 let mut dict = SharedDictBytes::default();
423 let v05_span = from_v04_span(span, &mut dict).unwrap();
424
425 let links_json = meta_json(&dict, &v05_span, "_dd.span_links").unwrap();
426 assert_eq!(
427 links_json,
428 "[{\"trace_id\":\"00000000000109320000000000003039\",\"span_id\":\"000000000000d431\",\"tracestate\":\"tracestate_value\",\"attributes\":{\"key\":\"val\"},\"flags\":1}]"
429 );
430 let events_json = meta_json(&dict, &v05_span, "events").unwrap();
431 assert_eq!(
432 events_json,
433 "[{\"time_unix_nano\":123,\"name\":\"ev1\",\"attributes\":{\"str_attr\":\"val\"}}]"
434 );
435 assert_eq!(v05_span.meta.len(), 3);
437 }
438
439 #[test]
442 fn from_v04_span_empty_links_events_no_meta_keys_test() {
443 let mut dict = SharedDictBytes::default();
444 let v05_span = from_v04_span(base_span(), &mut dict).unwrap();
445 assert_eq!(v05_span.meta.len(), 1);
446 assert!(meta_json(&dict, &v05_span, "_dd.span_links").is_none());
447 assert!(meta_json(&dict, &v05_span, "events").is_none());
448 }
449
450 #[test]
453 fn from_v04_span_drops_meta_struct_test() {
454 let mut span = base_span();
455 span.meta_struct = vec![(
456 BytesString::from("appsec"),
457 libdd_tinybytes::Bytes::from_static(&[0x01, 0x02, 0x03]),
458 )]
459 .into();
460
461 let mut dict = SharedDictBytes::default();
462 let v05_span = from_v04_span(span, &mut dict).unwrap();
463 assert_eq!(v05_span.meta.len(), 1);
464 assert!(meta_json(&dict, &v05_span, "appsec").is_none());
465 assert!(meta_json(&dict, &v05_span, "meta_struct").is_none());
466 }
467
468 #[test]
471 fn span_link_minimal_serialization_test() {
472 let links = vec![SpanLink::<BytesData> {
473 trace_id: 0xdead_beef,
474 trace_id_high: 0,
475 span_id: 0xfeed,
476 attributes: HashMap::new(),
477 tracestate: BytesString::from(""),
478 flags: 7,
479 }];
480 let json = serde_json::to_string(&SpanLinksSerializerV05::<BytesData>(&links)).unwrap();
481 assert_eq!(
482 json,
483 "[{\"trace_id\":\"000000000000000000000000deadbeef\",\"span_id\":\"000000000000feed\",\"flags\":7}]"
484 );
485 }
486
487 #[test]
490 fn span_link_flags_sentinel_bit_masked_test() {
491 let kept = vec![SpanLink::<BytesData> {
492 span_id: 1,
493 flags: 0x8000_0001,
494 ..Default::default()
495 }];
496 let json = serde_json::to_string(&SpanLinksSerializerV05::<BytesData>(&kept)).unwrap();
497 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
498 assert_eq!(parsed[0]["flags"], serde_json::json!(1));
499
500 let dropped = vec![SpanLink::<BytesData> {
501 span_id: 2,
502 flags: 0x8000_0000,
503 ..Default::default()
504 }];
505 let json = serde_json::to_string(&SpanLinksSerializerV05::<BytesData>(&dropped)).unwrap();
506 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
507 assert_eq!(parsed[0]["flags"], serde_json::json!(0));
508
509 let unset = vec![SpanLink::<BytesData> {
510 span_id: 3,
511 flags: 0,
512 ..Default::default()
513 }];
514 let json = serde_json::to_string(&SpanLinksSerializerV05::<BytesData>(&unset)).unwrap();
515 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
516 assert!(parsed[0].get("flags").is_none());
517 }
518
519 #[test]
521 fn span_links_multiple_serialization_test() {
522 let links = vec![
523 SpanLink::<BytesData> {
524 span_id: 0x22,
525 ..Default::default()
526 },
527 SpanLink::<BytesData> {
528 span_id: 0x44,
529 ..Default::default()
530 },
531 ];
532 let json = serde_json::to_string(&SpanLinksSerializerV05::<BytesData>(&links)).unwrap();
533 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
534 assert_eq!(parsed.as_array().unwrap().len(), 2);
535 assert_eq!(parsed[0]["span_id"], serde_json::json!("0000000000000022"));
536 assert_eq!(parsed[1]["span_id"], serde_json::json!("0000000000000044"));
537 }
538
539 #[test]
541 fn span_link_only_tracestate_serialization_test() {
542 let links = vec![SpanLink::<BytesData> {
543 span_id: 2,
544 tracestate: BytesString::from("ts"),
545 ..Default::default()
546 }];
547 let json = serde_json::to_string(&SpanLinksSerializerV05::<BytesData>(&links)).unwrap();
548 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
549 assert_eq!(parsed[0]["tracestate"], serde_json::json!("ts"));
550 assert!(parsed[0].get("attributes").is_none());
551 }
552
553 #[test]
555 fn span_link_only_attributes_serialization_test() {
556 let links = vec![SpanLink::<BytesData> {
557 span_id: 2,
558 attributes: HashMap::from([(BytesString::from("k"), BytesString::from("v"))]),
559 ..Default::default()
560 }];
561 let json = serde_json::to_string(&SpanLinksSerializerV05::<BytesData>(&links)).unwrap();
562 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
563 assert_eq!(parsed[0]["attributes"]["k"], serde_json::json!("v"));
564 assert!(parsed[0].get("tracestate").is_none());
565 }
566
567 #[test]
569 fn span_event_attribute_types_serialization_test() {
570 let events = vec![SpanEvent::<BytesData> {
571 time_unix_nano: 42,
572 name: BytesString::from("ev"),
573 attributes: HashMap::from([
574 (
575 BytesString::from("int_attr"),
576 AttributeAnyValue::SingleValue(AttributeArrayValue::Integer(-7)),
577 ),
578 (
579 BytesString::from("dbl_attr"),
580 AttributeAnyValue::SingleValue(AttributeArrayValue::Double(2.5)),
581 ),
582 (
583 BytesString::from("bool_attr"),
584 AttributeAnyValue::SingleValue(AttributeArrayValue::Boolean(true)),
585 ),
586 ]),
587 }];
588 let json = serde_json::to_string(&SpanEventsSerializerV05::<BytesData>(&events)).unwrap();
589 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
590 let attrs = &parsed[0]["attributes"];
591 assert_eq!(attrs["int_attr"], serde_json::json!(-7));
592 assert_eq!(attrs["dbl_attr"], serde_json::json!(2.5));
593 assert_eq!(attrs["bool_attr"], serde_json::json!(true));
594 assert_eq!(parsed[0]["time_unix_nano"], serde_json::json!(42));
595 assert_eq!(parsed[0]["name"], serde_json::json!("ev"));
596 }
597
598 #[test]
600 fn span_event_non_string_array_serialization_test() {
601 let events = vec![SpanEvent::<BytesData> {
602 time_unix_nano: 1,
603 name: BytesString::from("ev"),
604 attributes: HashMap::from([(
605 BytesString::from("arr"),
606 AttributeAnyValue::Array(vec![
607 AttributeArrayValue::Integer(1),
608 AttributeArrayValue::Boolean(true),
609 AttributeArrayValue::Double(3.5),
610 ]),
611 )]),
612 }];
613 let json = serde_json::to_string(&SpanEventsSerializerV05::<BytesData>(&events)).unwrap();
614 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
615 assert_eq!(
616 parsed[0]["attributes"]["arr"],
617 serde_json::json!([1, true, 3.5])
618 );
619 }
620
621 #[test]
625 fn attributes_serialized_in_sorted_key_order_test() {
626 let events = vec![SpanEvent::<BytesData> {
627 time_unix_nano: 1,
628 name: BytesString::from("ev"),
629 attributes: HashMap::from([
630 (
631 BytesString::from("zebra"),
632 AttributeAnyValue::SingleValue(AttributeArrayValue::Integer(1)),
633 ),
634 (
635 BytesString::from("alpha"),
636 AttributeAnyValue::SingleValue(AttributeArrayValue::Integer(2)),
637 ),
638 (
639 BytesString::from("mike"),
640 AttributeAnyValue::SingleValue(AttributeArrayValue::Integer(3)),
641 ),
642 ]),
643 }];
644 let json = serde_json::to_string(&SpanEventsSerializerV05::<BytesData>(&events)).unwrap();
645 assert_eq!(
646 json,
647 "[{\"time_unix_nano\":1,\"name\":\"ev\",\"attributes\":{\"alpha\":2,\"mike\":3,\"zebra\":1}}]"
648 );
649
650 let links = vec![SpanLink::<BytesData> {
651 span_id: 1,
652 attributes: HashMap::from([
653 (BytesString::from("zzz"), BytesString::from("1")),
654 (BytesString::from("aaa"), BytesString::from("2")),
655 ]),
656 ..Default::default()
657 }];
658 let json = serde_json::to_string(&SpanLinksSerializerV05::<BytesData>(&links)).unwrap();
659 assert!(
660 json.contains("\"attributes\":{\"aaa\":\"2\",\"zzz\":\"1\"}"),
661 "link attributes not sorted: {json}"
662 );
663 }
664
665 #[test]
667 fn span_event_empty_attributes_serialization_test() {
668 let events = vec![SpanEvent::<BytesData> {
669 time_unix_nano: 1,
670 name: BytesString::from("ev"),
671 attributes: HashMap::new(),
672 }];
673 let json = serde_json::to_string(&SpanEventsSerializerV05::<BytesData>(&events)).unwrap();
674 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
675 assert_eq!(parsed[0]["attributes"], serde_json::json!({}));
676 }
677}