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 pub fn as_meta_str(&self) -> &'static str {
36 match self {
37 SpanKind::Internal => "internal",
38 SpanKind::Server => "server",
39 SpanKind::Client => "client",
40 SpanKind::Producer => "producer",
41 SpanKind::Consumer => "consumer",
42 }
43 }
44}
45
46impl From<u32> for SpanKind {
47 fn from(kind: u32) -> Self {
49 match kind {
50 2 => SpanKind::Server,
51 3 => SpanKind::Client,
52 4 => SpanKind::Producer,
53 5 => SpanKind::Consumer,
54 _ => SpanKind::Internal,
55 }
56 }
57}
58
59#[derive(Debug)]
62pub enum AttributeValue<T: TraceData> {
63 String(T::Text),
64 Float(f64),
65 Int(i64),
66 Bool(bool),
67 Bytes(T::Bytes),
68 KeyValue(VecMap<T::Text, AttributeValue<T>>),
69 List(Vec<AttributeValue<T>>),
70}
71
72impl<T: TraceData> PartialEq for AttributeValue<T> {
76 fn eq(&self, other: &Self) -> bool {
77 match (self, other) {
78 (AttributeValue::String(a), AttributeValue::String(b)) => a == b,
79 (AttributeValue::Float(a), AttributeValue::Float(b)) => a == b,
80 (AttributeValue::Int(a), AttributeValue::Int(b)) => a == b,
81 (AttributeValue::Bool(a), AttributeValue::Bool(b)) => a == b,
82 (AttributeValue::Bytes(a), AttributeValue::Bytes(b)) => a == b,
83 (AttributeValue::KeyValue(a), AttributeValue::KeyValue(b)) => a.slow_compare(b),
84 (AttributeValue::List(a), AttributeValue::List(b)) => a == b,
85 _ => false,
86 }
87 }
88}
89
90#[derive(Debug, Default)]
103pub struct Span<T: TraceData> {
104 pub service: T::Text,
105 pub name: T::Text,
106 pub resource: T::Text,
107 pub r#type: T::Text,
108 pub span_id: u64,
109 pub parent_id: u64,
110 pub start: i64,
111 pub duration: i64,
112 pub error: bool,
113 pub span_kind: SpanKind,
114 pub env: T::Text,
115 pub version: T::Text,
116 pub component: T::Text,
117 pub attributes: VecMap<T::Text, AttributeValue<T>>,
118 pub span_links: ThinVec<SpanLink<T>>,
119 pub span_events: ThinVec<SpanEvent<T>>,
120}
121
122#[derive(Debug, Default)]
125pub struct SpanLink<T: TraceData> {
126 pub trace_id: [u8; 16],
127 pub span_id: u64,
128 pub attributes: VecMap<T::Text, AttributeValue<T>>,
129 pub tracestate: T::Text,
130 pub flags: u32,
131}
132
133#[derive(Debug, Default)]
136pub struct SpanEvent<T: TraceData> {
137 pub time_unix_nano: u64,
138 pub name: T::Text,
139 pub attributes: VecMap<T::Text, AttributeValue<T>>,
140}
141
142#[derive(Debug, Default)]
144pub struct TraceChunk<T: TraceData> {
145 pub trace_id: [u8; 16],
146 pub priority: Option<i32>,
147 pub origin: T::Text,
148 pub sampling_mechanism: Option<u32>,
149 pub dropped_trace: bool,
150 pub attributes: VecMap<T::Text, AttributeValue<T>>,
151 pub spans: Vec<Span<T>>,
152}
153
154#[derive(Debug, Default)]
156pub struct TracerPayload<T: TraceData> {
157 pub container_id: T::Text,
158 pub language_name: T::Text,
159 pub language_version: T::Text,
160 pub tracer_version: T::Text,
161 pub runtime_id: T::Text,
162 pub env: T::Text,
163 pub hostname: T::Text,
164 pub app_version: T::Text,
165 pub attributes: VecMap<T::Text, AttributeValue<T>>,
166 pub chunks: Vec<TraceChunk<T>>,
167}
168
169pub type SpanBytes = Span<BytesData>;
170pub type SpanLinkBytes = SpanLink<BytesData>;
171pub type SpanEventBytes = SpanEvent<BytesData>;
172pub type AttributeValueBytes = AttributeValue<BytesData>;
173pub type TraceChunkBytes = TraceChunk<BytesData>;
174pub type TracerPayloadBytes = TracerPayload<BytesData>;
175
176pub type SpanSlice<'a> = Span<SliceData<'a>>;
177pub type SpanLinkSlice<'a> = SpanLink<SliceData<'a>>;
178pub type SpanEventSlice<'a> = SpanEvent<SliceData<'a>>;
179pub type AttributeValueSlice<'a> = AttributeValue<SliceData<'a>>;
180pub type TraceChunkSlice<'a> = TraceChunk<SliceData<'a>>;
181pub type TracerPayloadSlice<'a> = TracerPayload<SliceData<'a>>;
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[test]
188 fn span_kind_default_is_internal() {
189 assert_eq!(SpanKind::default(), SpanKind::Internal);
190 }
191
192 #[test]
193 fn span_kind_from_meta() {
194 assert_eq!(SpanKind::from_meta("server"), SpanKind::Server);
195 assert_eq!(SpanKind::from_meta("client"), SpanKind::Client);
196 assert_eq!(SpanKind::from_meta("producer"), SpanKind::Producer);
197 assert_eq!(SpanKind::from_meta("consumer"), SpanKind::Consumer);
198 assert_eq!(SpanKind::from_meta("internal"), SpanKind::Internal);
199 assert_eq!(SpanKind::from_meta(""), SpanKind::Internal);
200 assert_eq!(SpanKind::from_meta("anything-else"), SpanKind::Internal);
201 }
202
203 #[test]
204 fn span_kind_repr_matches_otel_spec() {
205 assert_eq!(SpanKind::Internal as u32, 1);
206 assert_eq!(SpanKind::Server as u32, 2);
207 assert_eq!(SpanKind::Client as u32, 3);
208 assert_eq!(SpanKind::Producer as u32, 4);
209 assert_eq!(SpanKind::Consumer as u32, 5);
210 }
211
212 #[test]
213 fn span_default_has_internal_kind() {
214 let s = SpanBytes::default();
215 assert_eq!(s.span_kind, SpanKind::Internal);
216 assert!(!s.error);
217 assert!(s.attributes.is_empty());
218 }
219}