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, VecMap};
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: vec![(
85                BytesString::from("meta_field"),
86                BytesString::from("meta_value"),
87            )]
88            .into(),
89            metrics: vec![(BytesString::from("metrics_field"), 1.1)].into(),
90            meta_struct: VecMap::new(),
91            span_links: vec![],
92            span_events: vec![],
93        };
94
95        let mut dict = SharedDict::default();
96        let v05_span = from_v04_span(span, &mut dict).unwrap();
97
98        let get_index_from_str = |str: &str| -> u32 {
99            dict.iter()
100                .position(|s| s.as_str() == str)
101                .unwrap()
102                .try_into()
103                .unwrap()
104        };
105
106        assert_eq!(v05_span.service, get_index_from_str("service"));
107        assert_eq!(v05_span.name, get_index_from_str("name"));
108        assert_eq!(v05_span.resource, get_index_from_str("resource"));
109        assert_eq!(v05_span.r#type, get_index_from_str("type"));
110        assert_eq!(v05_span.trace_id, 1);
111        assert_eq!(v05_span.span_id, 1);
112        assert_eq!(v05_span.parent_id, 0);
113        assert_eq!(v05_span.start, 1);
114        assert_eq!(v05_span.duration, 111);
115        assert_eq!(v05_span.error, 0);
116        assert_eq!(v05_span.meta.len(), 1);
117        assert_eq!(v05_span.metrics.len(), 1);
118
119        assert_eq!(
120            *v05_span
121                .meta
122                .get(&get_index_from_str("meta_field"))
123                .unwrap(),
124            get_index_from_str("meta_value")
125        );
126        assert_eq!(
127            *v05_span
128                .metrics
129                .get(&get_index_from_str("metrics_field"))
130                .unwrap(),
131            1.1
132        );
133    }
134}