libdd_trace_utils/span/v1/
mod.rs1use crate::span::vec_map::VecMap;
5use crate::span::{BytesData, SliceData, TraceData};
6pub use thin_vec::ThinVec;
7
8#[repr(u32)]
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
12pub enum SpanKind {
13 #[default]
14 Internal = 1,
15 Server = 2,
16 Client = 3,
17 Producer = 4,
18 Consumer = 5,
19}
20
21impl SpanKind {
22 pub fn from_meta(s: &str) -> Self {
25 match s {
26 "server" => SpanKind::Server,
27 "client" => SpanKind::Client,
28 "producer" => SpanKind::Producer,
29 "consumer" => SpanKind::Consumer,
30 _ => SpanKind::Internal,
31 }
32 }
33}
34
35impl From<u32> for SpanKind {
36 fn from(kind: u32) -> Self {
38 match kind {
39 2 => SpanKind::Server,
40 3 => SpanKind::Client,
41 4 => SpanKind::Producer,
42 5 => SpanKind::Consumer,
43 _ => SpanKind::Internal,
44 }
45 }
46}
47
48#[derive(Debug)]
51pub enum AttributeValue<T: TraceData> {
52 String(T::Text),
53 Float(f64),
54 Int(i64),
55 Bool(bool),
56 Bytes(T::Bytes),
57 KeyValue(VecMap<T::Text, AttributeValue<T>>),
58 List(Vec<AttributeValue<T>>),
59}
60
61impl<T: TraceData> PartialEq for AttributeValue<T> {
65 fn eq(&self, other: &Self) -> bool {
66 match (self, other) {
67 (AttributeValue::String(a), AttributeValue::String(b)) => a == b,
68 (AttributeValue::Float(a), AttributeValue::Float(b)) => a == b,
69 (AttributeValue::Int(a), AttributeValue::Int(b)) => a == b,
70 (AttributeValue::Bool(a), AttributeValue::Bool(b)) => a == b,
71 (AttributeValue::Bytes(a), AttributeValue::Bytes(b)) => a == b,
72 (AttributeValue::KeyValue(a), AttributeValue::KeyValue(b)) => a.slow_compare(b),
73 (AttributeValue::List(a), AttributeValue::List(b)) => a == b,
74 _ => false,
75 }
76 }
77}
78
79#[derive(Debug, Default)]
92pub struct Span<T: TraceData> {
93 pub service: T::Text,
94 pub name: T::Text,
95 pub resource: T::Text,
96 pub r#type: T::Text,
97 pub span_id: u64,
98 pub parent_id: u64,
99 pub start: i64,
100 pub duration: i64,
101 pub error: bool,
102 pub span_kind: SpanKind,
103 pub env: T::Text,
104 pub version: T::Text,
105 pub component: T::Text,
106 pub attributes: VecMap<T::Text, AttributeValue<T>>,
107 pub span_links: ThinVec<SpanLink<T>>,
108 pub span_events: ThinVec<SpanEvent<T>>,
109}
110
111#[derive(Debug, Default)]
114pub struct SpanLink<T: TraceData> {
115 pub trace_id: [u8; 16],
116 pub span_id: u64,
117 pub attributes: VecMap<T::Text, AttributeValue<T>>,
118 pub tracestate: T::Text,
119 pub flags: u32,
120}
121
122#[derive(Debug, Default)]
125pub struct SpanEvent<T: TraceData> {
126 pub time_unix_nano: u64,
127 pub name: T::Text,
128 pub attributes: VecMap<T::Text, AttributeValue<T>>,
129}
130
131#[derive(Debug, Default)]
133pub struct TraceChunk<T: TraceData> {
134 pub trace_id: [u8; 16],
135 pub priority: Option<i32>,
136 pub origin: T::Text,
137 pub sampling_mechanism: Option<u32>,
138 pub dropped_trace: bool,
139 pub attributes: VecMap<T::Text, AttributeValue<T>>,
140 pub spans: Vec<Span<T>>,
141}
142
143#[derive(Debug, Default)]
145pub struct TracerPayload<T: TraceData> {
146 pub container_id: T::Text,
147 pub language_name: T::Text,
148 pub language_version: T::Text,
149 pub tracer_version: T::Text,
150 pub runtime_id: T::Text,
151 pub env: T::Text,
152 pub hostname: T::Text,
153 pub app_version: T::Text,
154 pub attributes: VecMap<T::Text, AttributeValue<T>>,
155 pub chunks: Vec<TraceChunk<T>>,
156}
157
158pub type SpanBytes = Span<BytesData>;
159pub type SpanLinkBytes = SpanLink<BytesData>;
160pub type SpanEventBytes = SpanEvent<BytesData>;
161pub type AttributeValueBytes = AttributeValue<BytesData>;
162pub type TraceChunkBytes = TraceChunk<BytesData>;
163pub type TracerPayloadBytes = TracerPayload<BytesData>;
164
165pub type SpanSlice<'a> = Span<SliceData<'a>>;
166pub type SpanLinkSlice<'a> = SpanLink<SliceData<'a>>;
167pub type SpanEventSlice<'a> = SpanEvent<SliceData<'a>>;
168pub type AttributeValueSlice<'a> = AttributeValue<SliceData<'a>>;
169pub type TraceChunkSlice<'a> = TraceChunk<SliceData<'a>>;
170pub type TracerPayloadSlice<'a> = TracerPayload<SliceData<'a>>;
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn span_kind_default_is_internal() {
178 assert_eq!(SpanKind::default(), SpanKind::Internal);
179 }
180
181 #[test]
182 fn span_kind_from_meta() {
183 assert_eq!(SpanKind::from_meta("server"), SpanKind::Server);
184 assert_eq!(SpanKind::from_meta("client"), SpanKind::Client);
185 assert_eq!(SpanKind::from_meta("producer"), SpanKind::Producer);
186 assert_eq!(SpanKind::from_meta("consumer"), SpanKind::Consumer);
187 assert_eq!(SpanKind::from_meta("internal"), SpanKind::Internal);
188 assert_eq!(SpanKind::from_meta(""), SpanKind::Internal);
189 assert_eq!(SpanKind::from_meta("anything-else"), SpanKind::Internal);
190 }
191
192 #[test]
193 fn span_kind_repr_matches_otel_spec() {
194 assert_eq!(SpanKind::Internal as u32, 1);
195 assert_eq!(SpanKind::Server as u32, 2);
196 assert_eq!(SpanKind::Client as u32, 3);
197 assert_eq!(SpanKind::Producer as u32, 4);
198 assert_eq!(SpanKind::Consumer as u32, 5);
199 }
200
201 #[test]
202 fn span_default_has_internal_kind() {
203 let s = SpanBytes::default();
204 assert_eq!(s.span_kind, SpanKind::Internal);
205 assert!(!s.error);
206 assert!(s.attributes.is_empty());
207 }
208}