Skip to main content

saluki_core/data_model/event/trace/
mod.rs

1//! Traces.
2
3use saluki_common::collections::FastHashMap;
4use saluki_context::tags::SharedTagSet;
5use stringtheory::MetaString;
6
7/// Trace-level sampling metadata.
8///
9/// This struct stores sampling-related metadata that applies to the entire trace,
10/// typically set by the trace sampler and consumed by the encoder.
11#[derive(Clone, Debug, PartialEq)]
12pub struct TraceSampling {
13    /// Whether or not the trace was dropped during sampling.
14    pub dropped_trace: bool,
15
16    /// The sampling priority assigned to this trace.
17    ///
18    /// Common values include:
19    /// - `2`: Manual keep (user-requested)
20    /// - `1`: Auto keep (sampled in)
21    /// - `0`: Auto drop (sampled out)
22    /// - `-1`: Manual drop (user-requested drop)
23    pub priority: Option<i32>,
24
25    /// The decision maker identifier indicating which sampler made the sampling decision.
26    ///
27    /// Common values include:
28    /// - `-9`: Probabilistic sampler
29    /// - `-4`: Errors sampler
30    /// - `None`: No decision maker set
31    pub decision_maker: Option<MetaString>,
32
33    /// The OTLP sampling rate applied to this trace.
34    ///
35    /// This corresponds to the `_dd.otlp_sr` tag and represents the effective sampling rate
36    /// from the OTLP ingest path.
37    pub otlp_sampling_rate: Option<f64>,
38}
39
40impl TraceSampling {
41    /// Creates a new `TraceSampling` instance.
42    pub fn new(
43        dropped_trace: bool, priority: Option<i32>, decision_maker: Option<MetaString>, otlp_sampling_rate: Option<f64>,
44    ) -> Self {
45        Self {
46            dropped_trace,
47            priority,
48            decision_maker,
49            otlp_sampling_rate,
50        }
51    }
52}
53
54/// A trace event.
55///
56/// A trace is a collection of spans that represent a distributed trace.
57#[derive(Clone, Debug, PartialEq)]
58pub struct Trace {
59    /// The spans that make up this trace.
60    spans: Vec<Span>,
61    /// Resource-level tags associated with this trace.
62    ///
63    /// This is derived from the resource of the spans and used to construct the tracer payload.
64    resource_tags: SharedTagSet,
65    /// Trace-level sampling metadata.
66    ///
67    /// This field contains sampling decision information (priority, decision maker, rates)
68    /// that applies to the entire trace. It is set by the trace sampler component and consumed
69    /// by the encoder to populate trace chunk metadata.
70    sampling: Option<TraceSampling>,
71}
72
73impl Trace {
74    /// Creates a new `Trace` with the given spans.
75    pub fn new(spans: Vec<Span>, resource_tags: impl Into<SharedTagSet>) -> Self {
76        Self {
77            spans,
78            resource_tags: resource_tags.into(),
79            sampling: None,
80        }
81    }
82
83    /// Returns a reference to the spans in this trace.
84    pub fn spans(&self) -> &[Span] {
85        &self.spans
86    }
87
88    /// Returns a mutable reference to the spans in this trace.
89    pub fn spans_mut(&mut self) -> &mut [Span] {
90        &mut self.spans
91    }
92
93    /// Replaces the spans in this trace with the given spans.
94    pub fn set_spans(&mut self, spans: Vec<Span>) {
95        self.spans = spans;
96    }
97
98    /// Retains only the spans specified by the predicate.
99    ///
100    /// Returns the number of spans retained. If no spans match, the trace is left unchanged.
101    pub fn retain_spans<F>(&mut self, mut f: F) -> usize
102    where
103        F: FnMut(&Trace, &Span) -> bool,
104    {
105        if self.spans.is_empty() {
106            return 0;
107        }
108
109        let mut has_match = false;
110        for span in self.spans.iter() {
111            if f(self, span) {
112                has_match = true;
113                break;
114            }
115        }
116
117        if !has_match {
118            return 0;
119        }
120
121        let mut spans = std::mem::take(&mut self.spans);
122        spans.retain(|span| f(self, span));
123        spans.shrink_to_fit();
124        let _ = std::mem::replace(&mut self.spans, spans);
125
126        self.spans.len()
127    }
128
129    /// Remove spans only the spans specified by the predicate return true.
130    pub fn remove_spans<F>(&mut self, mut f: F)
131    where
132        F: FnMut(&Trace, &Span) -> bool,
133    {
134        if self.spans.is_empty() {
135            return;
136        }
137
138        let mut spans = std::mem::take(&mut self.spans);
139        spans.retain(|span| !f(self, span));
140        spans.shrink_to_fit();
141        let _ = std::mem::replace(&mut self.spans, spans);
142    }
143
144    /// Returns the resource-level tags associated with this trace.
145    pub fn resource_tags(&self) -> &SharedTagSet {
146        &self.resource_tags
147    }
148
149    /// Returns a reference to the trace-level sampling metadata, if present.
150    pub fn sampling(&self) -> Option<&TraceSampling> {
151        self.sampling.as_ref()
152    }
153
154    /// Sets the trace-level sampling metadata.
155    pub fn set_sampling(&mut self, sampling: Option<TraceSampling>) {
156        self.sampling = sampling;
157    }
158}
159
160/// A span event.
161#[derive(Clone, Debug, PartialEq, Default)]
162pub struct Span {
163    /// The name of the service associated with this span.
164    service: MetaString,
165    /// The operation name of this span.
166    name: MetaString,
167    /// The resource associated with this span.
168    resource: MetaString,
169    /// The trace identifier this span belongs to.
170    trace_id: u64,
171    /// The unique identifier of this span.
172    span_id: u64,
173    /// The identifier of this span's parent, if any.
174    parent_id: u64,
175    /// The start timestamp of this span in nanoseconds since Unix epoch.
176    start: u64,
177    /// The duration of this span in nanoseconds.
178    duration: u64,
179    /// Error flag represented as 0 (no error) or 1 (error).
180    error: i32,
181    /// String-valued tags attached to this span.
182    meta: FastHashMap<MetaString, MetaString>,
183    /// Numeric-valued tags attached to this span.
184    metrics: FastHashMap<MetaString, f64>,
185    /// Span type classification (e.g., web, db, lambda).
186    span_type: MetaString,
187    /// Structured metadata payloads.
188    meta_struct: FastHashMap<MetaString, Vec<u8>>,
189    /// Links describing relationships to other spans.
190    span_links: Vec<SpanLink>,
191    /// Events associated with this span.
192    span_events: Vec<SpanEvent>,
193}
194
195impl Span {
196    /// Creates a new `Span` with all required fields.
197    #[allow(clippy::too_many_arguments)]
198    pub fn new(
199        service: impl Into<MetaString>, name: impl Into<MetaString>, resource: impl Into<MetaString>,
200        span_type: impl Into<MetaString>, trace_id: u64, span_id: u64, parent_id: u64, start: u64, duration: u64,
201        error: i32,
202    ) -> Self {
203        Self {
204            service: service.into(),
205            name: name.into(),
206            resource: resource.into(),
207            span_type: span_type.into(),
208            trace_id,
209            span_id,
210            parent_id,
211            start,
212            duration,
213            error,
214            ..Self::default()
215        }
216    }
217
218    /// Sets the service name.
219    pub fn with_service(mut self, service: impl Into<MetaString>) -> Self {
220        self.service = service.into();
221        self
222    }
223
224    /// Sets the operation name.
225    pub fn with_name(mut self, name: impl Into<MetaString>) -> Self {
226        self.name = name.into();
227        self
228    }
229
230    /// Sets the resource name.
231    pub fn with_resource(mut self, resource: impl Into<MetaString>) -> Self {
232        self.resource = resource.into();
233        self
234    }
235
236    /// Sets the trace identifier.
237    pub fn with_trace_id(mut self, trace_id: u64) -> Self {
238        self.trace_id = trace_id;
239        self
240    }
241
242    /// Sets the span identifier.
243    pub fn with_span_id(mut self, span_id: u64) -> Self {
244        self.span_id = span_id;
245        self
246    }
247
248    /// Sets the parent span identifier.
249    pub fn with_parent_id(mut self, parent_id: u64) -> Self {
250        self.parent_id = parent_id;
251        self
252    }
253
254    /// Sets the start timestamp.
255    pub fn with_start(mut self, start: u64) -> Self {
256        self.start = start;
257        self
258    }
259
260    /// Sets the span duration.
261    pub fn with_duration(mut self, duration: u64) -> Self {
262        self.duration = duration;
263        self
264    }
265
266    /// Sets the error flag.
267    pub fn with_error(mut self, error: i32) -> Self {
268        self.error = error;
269        self
270    }
271
272    /// Sets the span type (e.g., web, db, lambda).
273    pub fn with_span_type(mut self, span_type: impl Into<MetaString>) -> Self {
274        self.span_type = span_type.into();
275        self
276    }
277
278    /// Replaces the string-valued tag map.
279    pub fn with_meta(mut self, meta: impl Into<Option<FastHashMap<MetaString, MetaString>>>) -> Self {
280        self.meta = meta.into().unwrap_or_default();
281        self
282    }
283
284    /// Replaces the numeric-valued tag map.
285    pub fn with_metrics(mut self, metrics: impl Into<Option<FastHashMap<MetaString, f64>>>) -> Self {
286        self.metrics = metrics.into().unwrap_or_default();
287        self
288    }
289
290    /// Replaces the structured metadata map.
291    pub fn with_meta_struct(mut self, meta_struct: impl Into<Option<FastHashMap<MetaString, Vec<u8>>>>) -> Self {
292        self.meta_struct = meta_struct.into().unwrap_or_default();
293        self
294    }
295
296    /// Replaces the span links collection.
297    pub fn with_span_links(mut self, span_links: impl Into<Option<Vec<SpanLink>>>) -> Self {
298        self.span_links = span_links.into().unwrap_or_default();
299        self
300    }
301
302    /// Replaces the span events collection.
303    pub fn with_span_events(mut self, span_events: impl Into<Option<Vec<SpanEvent>>>) -> Self {
304        self.span_events = span_events.into().unwrap_or_default();
305        self
306    }
307
308    /// Returns the service name.
309    pub fn service(&self) -> &str {
310        &self.service
311    }
312
313    /// Returns the operation name.
314    pub fn name(&self) -> &str {
315        &self.name
316    }
317
318    /// Returns the resource name.
319    pub fn resource(&self) -> &str {
320        &self.resource
321    }
322
323    /// Sets the resource name.
324    pub fn set_resource(&mut self, resource: impl Into<MetaString>) {
325        self.resource = resource.into();
326    }
327
328    /// Returns the trace identifier.
329    pub fn trace_id(&self) -> u64 {
330        self.trace_id
331    }
332
333    /// Returns the span identifier.
334    pub fn span_id(&self) -> u64 {
335        self.span_id
336    }
337
338    /// Returns the parent span identifier.
339    pub fn parent_id(&self) -> u64 {
340        self.parent_id
341    }
342
343    /// Returns the start timestamp.
344    pub fn start(&self) -> u64 {
345        self.start
346    }
347
348    /// Returns the span duration.
349    pub fn duration(&self) -> u64 {
350        self.duration
351    }
352
353    /// Returns the error flag.
354    pub fn error(&self) -> i32 {
355        self.error
356    }
357
358    /// Returns the span type.
359    pub fn span_type(&self) -> &str {
360        &self.span_type
361    }
362
363    /// Returns the string-valued tag map.
364    pub fn meta(&self) -> &FastHashMap<MetaString, MetaString> {
365        &self.meta
366    }
367
368    /// Returns a mutable reference to the meta map.
369    pub fn meta_mut(&mut self) -> &mut FastHashMap<MetaString, MetaString> {
370        &mut self.meta
371    }
372
373    /// Returns the numeric-valued tag map.
374    pub fn metrics(&self) -> &FastHashMap<MetaString, f64> {
375        &self.metrics
376    }
377
378    /// Returns a mutable reference to the metrics map.
379    pub fn metrics_mut(&mut self) -> &mut FastHashMap<MetaString, f64> {
380        &mut self.metrics
381    }
382
383    /// Returns the structured metadata map.
384    pub fn meta_struct(&self) -> &FastHashMap<MetaString, Vec<u8>> {
385        &self.meta_struct
386    }
387
388    /// Returns the span links collection.
389    pub fn span_links(&self) -> &[SpanLink] {
390        &self.span_links
391    }
392
393    /// Returns the span events collection.
394    pub fn span_events(&self) -> &[SpanEvent] {
395        &self.span_events
396    }
397}
398
399/// A link between spans describing a causal relationship.
400#[derive(Clone, Debug, PartialEq, Default)]
401pub struct SpanLink {
402    /// Trace identifier for the linked span.
403    trace_id: u64,
404    /// High bits of the trace identifier when 128-bit IDs are used.
405    trace_id_high: u64,
406    /// Span identifier for the linked span.
407    span_id: u64,
408    /// Additional attributes attached to the link.
409    attributes: FastHashMap<MetaString, MetaString>,
410    /// W3C tracestate value.
411    tracestate: MetaString,
412    /// W3C trace flags where the high bit must be set when provided.
413    flags: u32,
414}
415
416impl SpanLink {
417    /// Creates a new span link for the provided identifiers.
418    pub fn new(trace_id: u64, span_id: u64) -> Self {
419        Self {
420            trace_id,
421            span_id,
422            ..Self::default()
423        }
424    }
425
426    /// Sets the trace identifier.
427    pub fn with_trace_id(mut self, trace_id: u64) -> Self {
428        self.trace_id = trace_id;
429        self
430    }
431
432    /// Sets the high bits of the trace identifier.
433    pub fn with_trace_id_high(mut self, trace_id_high: u64) -> Self {
434        self.trace_id_high = trace_id_high;
435        self
436    }
437
438    /// Sets the span identifier.
439    pub fn with_span_id(mut self, span_id: u64) -> Self {
440        self.span_id = span_id;
441        self
442    }
443
444    /// Replaces the attributes map.
445    pub fn with_attributes(mut self, attributes: impl Into<Option<FastHashMap<MetaString, MetaString>>>) -> Self {
446        self.attributes = attributes.into().unwrap_or_default();
447        self
448    }
449
450    /// Sets the W3C tracestate value.
451    pub fn with_tracestate(mut self, tracestate: impl Into<MetaString>) -> Self {
452        self.tracestate = tracestate.into();
453        self
454    }
455
456    /// Sets the W3C trace flags.
457    pub fn with_flags(mut self, flags: u32) -> Self {
458        self.flags = flags;
459        self
460    }
461
462    /// Returns the trace identifier.
463    pub fn trace_id(&self) -> u64 {
464        self.trace_id
465    }
466
467    /// Returns the high bits of the trace identifier.
468    pub fn trace_id_high(&self) -> u64 {
469        self.trace_id_high
470    }
471
472    /// Returns the span identifier.
473    pub fn span_id(&self) -> u64 {
474        self.span_id
475    }
476
477    /// Returns the attributes map.
478    pub fn attributes(&self) -> &FastHashMap<MetaString, MetaString> {
479        &self.attributes
480    }
481
482    /// Returns the W3C tracestate value.
483    pub fn tracestate(&self) -> &str {
484        &self.tracestate
485    }
486
487    /// Returns the W3C trace flags.
488    pub fn flags(&self) -> u32 {
489        self.flags
490    }
491}
492
493/// An event associated with a span.
494#[derive(Clone, Debug, PartialEq, Default)]
495pub struct SpanEvent {
496    /// Event timestamp in nanoseconds since Unix epoch.
497    time_unix_nano: u64,
498    /// Event name.
499    name: MetaString,
500    /// Arbitrary attributes describing the event.
501    attributes: FastHashMap<MetaString, AttributeValue>,
502}
503
504impl SpanEvent {
505    /// Creates a new span event with the given timestamp and name.
506    pub fn new(time_unix_nano: u64, name: impl Into<MetaString>) -> Self {
507        Self {
508            time_unix_nano,
509            name: name.into(),
510            ..Self::default()
511        }
512    }
513
514    /// Sets the event timestamp.
515    pub fn with_time_unix_nano(mut self, time_unix_nano: u64) -> Self {
516        self.time_unix_nano = time_unix_nano;
517        self
518    }
519
520    /// Sets the event name.
521    pub fn with_name(mut self, name: impl Into<MetaString>) -> Self {
522        self.name = name.into();
523        self
524    }
525
526    /// Replaces the attributes map.
527    pub fn with_attributes(mut self, attributes: impl Into<Option<FastHashMap<MetaString, AttributeValue>>>) -> Self {
528        self.attributes = attributes.into().unwrap_or_default();
529        self
530    }
531
532    /// Returns the event timestamp.
533    pub fn time_unix_nano(&self) -> u64 {
534        self.time_unix_nano
535    }
536
537    /// Returns the event name.
538    pub fn name(&self) -> &str {
539        &self.name
540    }
541
542    /// Returns the attributes map.
543    pub fn attributes(&self) -> &FastHashMap<MetaString, AttributeValue> {
544        &self.attributes
545    }
546}
547
548/// Values supported for span and event attributes.
549#[derive(Clone, Debug, PartialEq)]
550pub enum AttributeValue {
551    /// String attribute value.
552    String(MetaString),
553    /// Boolean attribute value.
554    Bool(bool),
555    /// Integer attribute value.
556    Int(i64),
557    /// Floating-point attribute value.
558    Double(f64),
559    /// Array attribute values.
560    Array(Vec<AttributeScalarValue>),
561}
562
563/// Scalar values supported inside attribute arrays.
564#[derive(Clone, Debug, PartialEq)]
565pub enum AttributeScalarValue {
566    /// String array value.
567    String(MetaString),
568    /// Boolean array value.
569    Bool(bool),
570    /// Integer array value.
571    Int(i64),
572    /// Floating-point array value.
573    Double(f64),
574}