opentelemetry_sdk/trace/
mod.rs

1//! # OpenTelemetry Trace SDK
2//!
3//! The tracing SDK consist of a few main structs:
4//!
5//! * The [`Tracer`] struct which performs all tracing operations.
6//! * The [`Span`] struct with is a mutable object storing information about the
7//! current operation execution.
8//! * The [`TracerProvider`] struct which configures and produces [`Tracer`]s.
9mod config;
10mod events;
11mod id_generator;
12mod links;
13mod provider;
14mod sampler;
15mod span;
16mod span_limit;
17mod span_processor;
18mod tracer;
19
20pub use config::{config, Config};
21pub use events::SpanEvents;
22
23pub use id_generator::{IdGenerator, RandomIdGenerator};
24pub use links::SpanLinks;
25pub use provider::{Builder, TracerProvider};
26pub use sampler::{Sampler, ShouldSample};
27pub use span::Span;
28pub use span_limit::SpanLimits;
29pub use span_processor::{
30    BatchConfig, BatchConfigBuilder, BatchSpanProcessor, BatchSpanProcessorBuilder,
31    SimpleSpanProcessor, SpanProcessor,
32};
33pub use tracer::Tracer;
34
35#[cfg(feature = "jaeger_remote_sampler")]
36pub use sampler::{JaegerRemoteSampler, JaegerRemoteSamplerBuilder};
37
38#[cfg(test)]
39mod runtime_tests;
40
41#[cfg(all(test, feature = "testing"))]
42mod tests {
43    use super::*;
44    use crate::{
45        testing::trace::InMemorySpanExporterBuilder,
46        trace::span_limit::{DEFAULT_MAX_EVENT_PER_SPAN, DEFAULT_MAX_LINKS_PER_SPAN},
47    };
48    use opentelemetry::testing::trace::TestSpan;
49    use opentelemetry::trace::{
50        SamplingDecision, SamplingResult, SpanKind, Status, TraceContextExt, TraceState,
51    };
52    use opentelemetry::{
53        trace::{
54            Event, Link, Span, SpanBuilder, SpanContext, SpanId, TraceFlags, TraceId, Tracer,
55            TracerProvider as _,
56        },
57        Context, KeyValue,
58    };
59
60    #[test]
61    fn tracer_in_span() {
62        // Arrange
63        let exporter = InMemorySpanExporterBuilder::new().build();
64        let provider = TracerProvider::builder()
65            .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
66            .build();
67
68        // Act
69        let tracer = provider.tracer("test_tracer");
70        tracer.in_span("span_name", |cx| {
71            let span = cx.span();
72            assert!(span.is_recording());
73            span.update_name("span_name_updated");
74            span.set_attribute(KeyValue::new("attribute1", "value1"));
75            span.add_event("test-event".to_string(), vec![]);
76        });
77
78        // Assert
79        let exported_spans = exporter
80            .get_finished_spans()
81            .expect("Spans are expected to be exported.");
82        assert_eq!(exported_spans.len(), 1);
83        let span = &exported_spans[0];
84        assert_eq!(span.name, "span_name_updated");
85        assert_eq!(span.instrumentation_lib.name, "test_tracer");
86        assert_eq!(span.attributes.len(), 1);
87        assert_eq!(span.events.len(), 1);
88        assert_eq!(span.events[0].name, "test-event");
89        assert_eq!(span.span_context.trace_flags(), TraceFlags::SAMPLED);
90        assert!(!span.span_context.is_remote());
91        assert_eq!(span.status, Status::Unset);
92    }
93
94    #[test]
95    fn tracer_start() {
96        // Arrange
97        let exporter = InMemorySpanExporterBuilder::new().build();
98        let provider = TracerProvider::builder()
99            .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
100            .build();
101
102        // Act
103        let tracer = provider.tracer("test_tracer");
104        let mut span = tracer.start("span_name");
105        span.set_attribute(KeyValue::new("attribute1", "value1"));
106        span.add_event("test-event".to_string(), vec![]);
107        span.set_status(Status::error("cancelled"));
108        span.end();
109
110        // After span end, further operations should not have any effect
111        span.update_name("span_name_updated");
112
113        // Assert
114        let exported_spans = exporter
115            .get_finished_spans()
116            .expect("Spans are expected to be exported.");
117        assert_eq!(exported_spans.len(), 1);
118        let span = &exported_spans[0];
119        assert_eq!(span.name, "span_name");
120        assert_eq!(span.instrumentation_lib.name, "test_tracer");
121        assert_eq!(span.attributes.len(), 1);
122        assert_eq!(span.events.len(), 1);
123        assert_eq!(span.events[0].name, "test-event");
124        assert_eq!(span.span_context.trace_flags(), TraceFlags::SAMPLED);
125        assert!(!span.span_context.is_remote());
126        let status_expected = Status::error("cancelled");
127        assert_eq!(span.status, status_expected);
128    }
129
130    #[test]
131    fn tracer_span_builder() {
132        // Arrange
133        let exporter = InMemorySpanExporterBuilder::new().build();
134        let provider = TracerProvider::builder()
135            .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
136            .build();
137
138        // Act
139        let tracer = provider.tracer("test_tracer");
140        let mut span = tracer
141            .span_builder("span_name")
142            .with_kind(SpanKind::Server)
143            .start(&tracer);
144        span.set_attribute(KeyValue::new("attribute1", "value1"));
145        span.add_event("test-event".to_string(), vec![]);
146        span.set_status(Status::Ok);
147        drop(span);
148
149        // Assert
150        let exported_spans = exporter
151            .get_finished_spans()
152            .expect("Spans are expected to be exported.");
153        assert_eq!(exported_spans.len(), 1);
154        let span = &exported_spans[0];
155        assert_eq!(span.name, "span_name");
156        assert_eq!(span.span_kind, SpanKind::Server);
157        assert_eq!(span.instrumentation_lib.name, "test_tracer");
158        assert_eq!(span.attributes.len(), 1);
159        assert_eq!(span.events.len(), 1);
160        assert_eq!(span.events[0].name, "test-event");
161        assert_eq!(span.span_context.trace_flags(), TraceFlags::SAMPLED);
162        assert!(!span.span_context.is_remote());
163        assert_eq!(span.status, Status::Ok);
164    }
165
166    #[test]
167    fn exceed_span_links_limit() {
168        // Arrange
169        let exporter = InMemorySpanExporterBuilder::new().build();
170        let provider = TracerProvider::builder()
171            .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
172            .build();
173
174        // Act
175        let tracer = provider.tracer("test_tracer");
176
177        let mut links = Vec::new();
178        for _i in 0..(DEFAULT_MAX_LINKS_PER_SPAN * 2) {
179            links.push(Link::with_context(SpanContext::new(
180                TraceId::from_u128(12),
181                SpanId::from_u64(12),
182                TraceFlags::default(),
183                false,
184                Default::default(),
185            )))
186        }
187
188        let span_builder = SpanBuilder::from_name("span_name").with_links(links);
189        let mut span = tracer.build(span_builder);
190        span.end();
191
192        // Assert
193        let exported_spans = exporter
194            .get_finished_spans()
195            .expect("Spans are expected to be exported.");
196        assert_eq!(exported_spans.len(), 1);
197        let span = &exported_spans[0];
198        assert_eq!(span.name, "span_name");
199        assert_eq!(span.links.len(), DEFAULT_MAX_LINKS_PER_SPAN as usize);
200    }
201
202    #[test]
203    fn exceed_span_events_limit() {
204        // Arrange
205        let exporter = InMemorySpanExporterBuilder::new().build();
206        let provider = TracerProvider::builder()
207            .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
208            .build();
209
210        // Act
211        let tracer = provider.tracer("test_tracer");
212
213        let mut events = Vec::new();
214        for _i in 0..(DEFAULT_MAX_EVENT_PER_SPAN * 2) {
215            events.push(Event::with_name("test event"))
216        }
217
218        // add events via span builder
219        let span_builder = SpanBuilder::from_name("span_name").with_events(events);
220        let mut span = tracer.build(span_builder);
221
222        // add events using span api after building the span
223        span.add_event("test event again, after span builder", Vec::new());
224        span.add_event("test event once again, after span builder", Vec::new());
225        span.end();
226
227        // Assert
228        let exported_spans = exporter
229            .get_finished_spans()
230            .expect("Spans are expected to be exported.");
231        assert_eq!(exported_spans.len(), 1);
232        let span = &exported_spans[0];
233        assert_eq!(span.name, "span_name");
234        assert_eq!(span.events.len(), DEFAULT_MAX_EVENT_PER_SPAN as usize);
235        assert_eq!(span.events.dropped_count, DEFAULT_MAX_EVENT_PER_SPAN + 2);
236    }
237
238    #[test]
239    fn trace_state_for_dropped_sampler() {
240        let exporter = InMemorySpanExporterBuilder::new().build();
241        let provider = TracerProvider::builder()
242            .with_config(Config::default().with_sampler(Sampler::AlwaysOff))
243            .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
244            .build();
245
246        let tracer = provider.tracer("test");
247        let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
248
249        let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
250            TraceId::from_u128(10000),
251            SpanId::from_u64(20),
252            TraceFlags::SAMPLED,
253            true,
254            trace_state.clone(),
255        )));
256
257        let span = tracer.start_with_context("span", &parent_context);
258        assert_eq!(
259            span.span_context().trace_state().get("foo"),
260            trace_state.get("foo")
261        )
262    }
263
264    #[derive(Clone, Debug, Default)]
265    struct TestRecordOnlySampler {}
266
267    impl ShouldSample for TestRecordOnlySampler {
268        fn should_sample(
269            &self,
270            parent_context: Option<&Context>,
271            _trace_id: TraceId,
272            _name: &str,
273            _span_kind: &SpanKind,
274            _attributes: &[KeyValue],
275            _links: &[Link],
276        ) -> SamplingResult {
277            let trace_state = parent_context
278                .unwrap()
279                .span()
280                .span_context()
281                .trace_state()
282                .clone();
283            SamplingResult {
284                decision: SamplingDecision::RecordOnly,
285                attributes: vec![KeyValue::new("record_only_key", "record_only_value")],
286                trace_state,
287            }
288        }
289    }
290
291    #[test]
292    fn trace_state_for_record_only_sampler() {
293        let exporter = InMemorySpanExporterBuilder::new().build();
294        let provider = TracerProvider::builder()
295            .with_config(Config::default().with_sampler(TestRecordOnlySampler::default()))
296            .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
297            .build();
298
299        let tracer = provider.tracer("test");
300        let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
301
302        let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
303            TraceId::from_u128(10000),
304            SpanId::from_u64(20),
305            TraceFlags::SAMPLED,
306            true,
307            trace_state.clone(),
308        )));
309
310        let span = tracer.build_with_context(
311            SpanBuilder::from_name("span")
312                .with_attributes(vec![KeyValue::new("extra_attr_key", "extra_attr_value")]),
313            &parent_context,
314        );
315        assert!(!span.span_context().trace_flags().is_sampled());
316        assert_eq!(
317            span.exported_data().unwrap().attributes,
318            vec![
319                KeyValue::new("extra_attr_key", "extra_attr_value"),
320                KeyValue::new("record_only_key", "record_only_value")
321            ]
322        );
323        assert_eq!(span.span_context().trace_state().get("foo"), Some("bar"));
324    }
325
326    #[test]
327    fn tracer_attributes() {
328        let provider = TracerProvider::builder().build();
329        let tracer = provider
330            .tracer_builder("test_tracer")
331            .with_attributes(vec![KeyValue::new("test_k", "test_v")])
332            .build();
333        let instrumentation_library = tracer.instrumentation_library();
334        let attributes = &instrumentation_library.attributes;
335        assert_eq!(attributes.len(), 1);
336        assert_eq!(attributes[0].key, "test_k".into());
337        assert_eq!(attributes[0].value, "test_v".into());
338    }
339
340    #[test]
341    #[allow(deprecated)]
342    fn versioned_tracer_options() {
343        let provider = TracerProvider::builder().build();
344        let tracer = provider.versioned_tracer(
345            "test_tracer",
346            Some(String::from("v1.2.3")),
347            Some(String::from("https://opentelemetry.io/schema/1.0.0")),
348            Some(vec![(KeyValue::new("test_k", "test_v"))]),
349        );
350        let instrumentation_library = tracer.instrumentation_library();
351        let attributes = &instrumentation_library.attributes;
352        assert_eq!(instrumentation_library.name, "test_tracer");
353        assert_eq!(instrumentation_library.version, Some("v1.2.3".into()));
354        assert_eq!(
355            instrumentation_library.schema_url,
356            Some("https://opentelemetry.io/schema/1.0.0".into())
357        );
358        assert_eq!(attributes.len(), 1);
359        assert_eq!(attributes[0].key, "test_k".into());
360        assert_eq!(attributes[0].value, "test_v".into());
361    }
362}