Skip to main content

libdd_trace_utils/span/v05/
mod.rs

1// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/
2// SPDX-License-Identifier: Apache-2.0
3
4pub mod dict;
5
6use crate::span::{v05::dict::SharedDict, TraceData};
7use anyhow::Result;
8use serde::Serialize;
9use std::collections::HashMap;
10
11/// Structure that represent a TraceChunk Span which String fields are interned in a shared
12/// dictionary. The number of elements is fixed by the spec and they all need to be serialized, in
13/// case of adding more items the constant msgpack_decoder::v05::SPAN_ELEM_COUNT need to be
14/// updated.
15#[derive(Clone, Debug, Default, PartialEq, Serialize)]
16pub struct Span {
17    pub service: u32,
18    pub name: u32,
19    pub resource: u32,
20    pub trace_id: u64,
21    pub span_id: u64,
22    pub parent_id: u64,
23    pub start: i64,
24    pub duration: i64,
25    pub error: i32,
26    pub meta: HashMap<u32, u32>,
27    pub metrics: HashMap<u32, f64>,
28    pub r#type: u32,
29}
30
31pub fn from_v04_span<T: TraceData>(
32    span: crate::span::v04::Span<T>,
33    dict: &mut SharedDict<T::Text>,
34) -> Result<Span> {
35    let meta_len = span.meta.len();
36    let metrics_len = span.metrics.len();
37    Ok(Span {
38        service: dict.get_or_insert(span.service)?,
39        name: dict.get_or_insert(span.name)?,
40        resource: dict.get_or_insert(span.resource)?,
41        trace_id: span.trace_id as u64,
42        span_id: span.span_id,
43        parent_id: span.parent_id,
44        start: span.start,
45        duration: span.duration,
46        error: span.error,
47        meta: span.meta.into_iter().try_fold(
48            HashMap::with_capacity(meta_len),
49            |mut meta, (k, v)| -> anyhow::Result<HashMap<u32, u32>> {
50                meta.insert(dict.get_or_insert(k)?, dict.get_or_insert(v)?);
51                Ok(meta)
52            },
53        )?,
54        metrics: span.metrics.into_iter().try_fold(
55            HashMap::with_capacity(metrics_len),
56            |mut metrics, (k, v)| -> anyhow::Result<HashMap<u32, f64>> {
57                metrics.insert(dict.get_or_insert(k)?, v);
58                Ok(metrics)
59            },
60        )?,
61        r#type: dict.get_or_insert(span.r#type)?,
62    })
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use crate::span::v04::SpanBytes;
69    use libdd_tinybytes::BytesString;
70
71    #[test]
72    fn from_span_bytes_test() {
73        let span = SpanBytes {
74            service: BytesString::from("service"),
75            name: BytesString::from("name"),
76            resource: BytesString::from("resource"),
77            r#type: BytesString::from("type"),
78            trace_id: 1,
79            span_id: 1,
80            parent_id: 0,
81            start: 1,
82            duration: 111,
83            error: 0,
84            meta: HashMap::from([(
85                BytesString::from("meta_field"),
86                BytesString::from("meta_value"),
87            )]),
88            metrics: HashMap::from([(BytesString::from("metrics_field"), 1.1)]),
89            meta_struct: HashMap::new(),
90            span_links: vec![],
91            span_events: vec![],
92        };
93
94        let mut dict = SharedDict::default();
95        let v05_span = from_v04_span(span, &mut dict).unwrap();
96
97        let get_index_from_str = |str: &str| -> u32 {
98            dict.iter()
99                .position(|s| s.as_str() == str)
100                .unwrap()
101                .try_into()
102                .unwrap()
103        };
104
105        assert_eq!(v05_span.service, get_index_from_str("service"));
106        assert_eq!(v05_span.name, get_index_from_str("name"));
107        assert_eq!(v05_span.resource, get_index_from_str("resource"));
108        assert_eq!(v05_span.r#type, get_index_from_str("type"));
109        assert_eq!(v05_span.trace_id, 1);
110        assert_eq!(v05_span.span_id, 1);
111        assert_eq!(v05_span.parent_id, 0);
112        assert_eq!(v05_span.start, 1);
113        assert_eq!(v05_span.duration, 111);
114        assert_eq!(v05_span.error, 0);
115        assert_eq!(v05_span.meta.len(), 1);
116        assert_eq!(v05_span.metrics.len(), 1);
117
118        assert_eq!(
119            *v05_span
120                .meta
121                .get(&get_index_from_str("meta_field"))
122                .unwrap(),
123            get_index_from_str("meta_value")
124        );
125        assert_eq!(
126            *v05_span
127                .metrics
128                .get(&get_index_from_str("metrics_field"))
129                .unwrap(),
130            1.1
131        );
132    }
133}