opentelemetry_sdk/trace/
mod.rs

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