1mod 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")]
20pub mod span_processor_with_async_runtime;
22mod tracer;
23
24pub use config::Config;
25pub use events::SpanEvents;
26pub use export::{SpanData, SpanExporter};
27
28#[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, SamplingDecision, SamplingResult, 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; #[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 use super::*;
60 use crate::error::OTelSdkResult;
61 use crate::trace::{SamplingDecision, SamplingResult};
62 use crate::{
63 trace::span_limit::{DEFAULT_MAX_EVENT_PER_SPAN, DEFAULT_MAX_LINKS_PER_SPAN},
64 trace::{InMemorySpanExporter, InMemorySpanExporterBuilder},
65 };
66 use opentelemetry::{
67 baggage::BaggageExt,
68 trace::{get_active_span, SpanKind, Status, TraceContextExt, TraceState},
69 };
70 use opentelemetry::{testing::trace::TestSpan, InstrumentationScope};
71 use opentelemetry::{
72 trace::{
73 Event, Link, Span, SpanBuilder, SpanContext, SpanId, TraceFlags, TraceId, Tracer,
74 TracerProvider,
75 },
76 Context, KeyValue,
77 };
78 use std::time::Duration;
79
80 #[test]
82 fn nested_span_in_get_active_span_with_simple_processor() {
83 let exporter = InMemorySpanExporterBuilder::new().build();
84 let provider = SdkTracerProvider::builder()
85 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
86 .build();
87 let tracer = provider.tracer("test_tracer");
88
89 get_active_span(|_span| {
90 let _nested = tracer.span_builder("nested").start(&tracer);
91 });
92 }
93
94 #[test]
95 fn span_modification_via_context() {
96 let exporter = InMemorySpanExporterBuilder::new().build();
97 let provider = SdkTracerProvider::builder()
98 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
99 .build();
100 let tracer = provider.tracer("test_tracer");
101
102 #[derive(Debug, PartialEq)]
103 struct ValueA(u64);
104
105 let span = tracer.start("span-name");
106
107 let cx = Context::current();
109 assert!(!cx.has_active_span());
110
111 let cx_with_span = cx.with_span(span);
113 assert!(cx_with_span.has_active_span());
114 assert!(!cx.has_active_span());
115
116 let span_ref = cx_with_span.span();
120 span_ref.set_attribute(KeyValue::new("attribute1", "value1"));
121
122 let cx_with_span_and_more = cx_with_span.with_value(ValueA(1));
124
125 let span_ref_new = cx_with_span_and_more.span();
128 span_ref_new.set_attribute(KeyValue::new("attribute2", "value2"));
129
130 span_ref_new.end();
131
132 let exported_spans = exporter
133 .get_finished_spans()
134 .expect("Spans are expected to be exported.");
135 assert_eq!(exported_spans.len(), 1);
137 let span = &exported_spans[0];
138 assert_eq!(span.attributes.len(), 2);
139 }
140
141 #[derive(Debug)]
142 struct BaggageInspectingSpanProcessor;
143 impl SpanProcessor for BaggageInspectingSpanProcessor {
144 fn on_start(&self, span: &mut crate::trace::Span, cx: &Context) {
145 let baggage = cx.baggage();
146 if let Some(baggage_value) = baggage.get("bag-key") {
147 span.set_attribute(KeyValue::new("bag-key", baggage_value.to_string()));
148 } else {
149 unreachable!("Baggage should be present in the context");
150 }
151 }
152
153 fn on_end(&self, span: SpanData) {
154 Context::current();
157
158 assert!(
164 span.attributes
165 .iter()
166 .any(|kv| kv.key.as_str() == "bag-key"),
167 "Baggage should have been stored as span attribute in on_start"
168 );
169 }
170
171 fn force_flush(&self) -> crate::error::OTelSdkResult {
172 Ok(())
173 }
174
175 fn shutdown_with_timeout(&self, _timeout: Duration) -> OTelSdkResult {
176 Ok(())
177 }
178 }
179
180 #[test]
181 fn span_and_baggage() {
182 let provider = SdkTracerProvider::builder()
183 .with_span_processor(BaggageInspectingSpanProcessor)
184 .build();
185
186 let cx_with_baggage =
187 Context::current_with_baggage(vec![KeyValue::new("bag-key", "bag-value")]);
188
189 assert_eq!(
191 cx_with_baggage
192 .baggage()
193 .get("bag-key")
194 .unwrap()
195 .to_string(),
196 "bag-value"
197 );
198
199 let _cx_guard1 = cx_with_baggage.attach();
201 assert_eq!(
203 Context::current()
204 .baggage()
205 .get("bag-key")
206 .unwrap()
207 .to_string(),
208 "bag-value"
209 );
210
211 let tracer = provider.tracer("test_tracer");
212 let mut span = tracer
213 .span_builder("span-name")
214 .start_with_context(&tracer, &Context::current());
215 span.set_attribute(KeyValue::new("attribute1", "value1"));
216
217 let cx = Context::current();
220 assert!(!cx.has_active_span());
221
222 let cx_with_baggage_and_span = cx.with_span(span);
224 assert!(cx_with_baggage_and_span.has_active_span());
225 assert_eq!(
226 cx_with_baggage_and_span
227 .baggage()
228 .get("bag-key")
229 .unwrap()
230 .to_string(),
231 "bag-value"
232 );
233
234 let _cx_guard2 = cx_with_baggage_and_span.attach();
235 assert!(Context::current().has_active_span());
237 assert_eq!(
238 Context::current()
239 .baggage()
240 .get("bag-key")
241 .unwrap()
242 .to_string(),
243 "bag-value"
244 );
245 }
246
247 #[test]
248 fn tracer_in_span() {
249 let exporter = InMemorySpanExporterBuilder::new().build();
251 let provider = SdkTracerProvider::builder()
252 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
253 .build();
254
255 let tracer = provider.tracer("test_tracer");
257 tracer.in_span("span_name", |cx| {
258 let span = cx.span();
259 assert!(span.is_recording());
260 span.update_name("span_name_updated");
261 span.set_attribute(KeyValue::new("attribute1", "value1"));
262 span.add_event("test-event".to_string(), vec![]);
263 span.add_link(
264 SpanContext::new(
265 TraceId::from(47),
266 SpanId::from(11),
267 TraceFlags::default(),
268 false,
269 Default::default(),
270 ),
271 vec![],
272 );
273 });
274
275 let exported_spans = exporter
277 .get_finished_spans()
278 .expect("Spans are expected to be exported.");
279 assert_eq!(exported_spans.len(), 1);
280 let span = &exported_spans[0];
281 assert_eq!(span.name, "span_name_updated");
282 assert_eq!(span.instrumentation_scope.name(), "test_tracer");
283 assert_eq!(span.attributes.len(), 1);
284 assert_eq!(span.events.len(), 1);
285 assert_eq!(span.events[0].name, "test-event");
286 assert_eq!(span.links.len(), 1);
287 assert_eq!(span.links[0].span_context.trace_id(), TraceId::from(47));
288 assert_eq!(span.links[0].span_context.span_id(), SpanId::from(11));
289 assert_eq!(span.span_context.trace_flags(), TraceFlags::SAMPLED);
290 assert!(!span.span_context.is_remote());
291 assert_eq!(span.status, Status::Unset);
292 }
293
294 #[test]
295 fn tracer_start() {
296 let exporter = InMemorySpanExporterBuilder::new().build();
298 let provider = SdkTracerProvider::builder()
299 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
300 .build();
301
302 let tracer = provider.tracer("test_tracer");
304 let mut span = tracer.start("span_name");
305 span.set_attribute(KeyValue::new("attribute1", "value1"));
306 span.add_event("test-event".to_string(), vec![]);
307 span.set_status(Status::error("cancelled"));
308 span.end();
309
310 span.update_name("span_name_updated");
312
313 let exported_spans = exporter
315 .get_finished_spans()
316 .expect("Spans are expected to be exported.");
317 assert_eq!(exported_spans.len(), 1);
318 let span = &exported_spans[0];
319 assert_eq!(span.name, "span_name");
320 assert_eq!(span.instrumentation_scope.name(), "test_tracer");
321 assert_eq!(span.attributes.len(), 1);
322 assert_eq!(span.events.len(), 1);
323 assert_eq!(span.events[0].name, "test-event");
324 assert_eq!(span.span_context.trace_flags(), TraceFlags::SAMPLED);
325 assert!(!span.span_context.is_remote());
326 let status_expected = Status::error("cancelled");
327 assert_eq!(span.status, status_expected);
328 }
329
330 #[test]
331 fn tracer_span_builder() {
332 let exporter = InMemorySpanExporterBuilder::new().build();
334 let provider = SdkTracerProvider::builder()
335 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
336 .build();
337
338 let tracer = provider.tracer("test_tracer");
340 let mut span = tracer
341 .span_builder("span_name")
342 .with_kind(SpanKind::Server)
343 .start(&tracer);
344 span.set_attribute(KeyValue::new("attribute1", "value1"));
345 span.add_event("test-event".to_string(), vec![]);
346 span.set_status(Status::Ok);
347 drop(span);
348
349 let exported_spans = exporter
351 .get_finished_spans()
352 .expect("Spans are expected to be exported.");
353 assert_eq!(exported_spans.len(), 1);
354 let span = &exported_spans[0];
355 assert_eq!(span.name, "span_name");
356 assert_eq!(span.span_kind, SpanKind::Server);
357 assert_eq!(span.instrumentation_scope.name(), "test_tracer");
358 assert_eq!(span.attributes.len(), 1);
359 assert_eq!(span.events.len(), 1);
360 assert_eq!(span.events[0].name, "test-event");
361 assert_eq!(span.span_context.trace_flags(), TraceFlags::SAMPLED);
362 assert!(!span.span_context.is_remote());
363 assert_eq!(span.status, Status::Ok);
364 }
365
366 #[test]
367 fn exceed_span_links_limit() {
368 let exporter = InMemorySpanExporterBuilder::new().build();
370 let provider = SdkTracerProvider::builder()
371 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
372 .build();
373
374 let tracer = provider.tracer("test_tracer");
376
377 let mut links = Vec::new();
378 for _i in 0..(DEFAULT_MAX_LINKS_PER_SPAN * 2) {
379 links.push(Link::with_context(SpanContext::new(
380 TraceId::from(12),
381 SpanId::from(12),
382 TraceFlags::default(),
383 false,
384 Default::default(),
385 )))
386 }
387
388 let span_builder = SpanBuilder::from_name("span_name").with_links(links);
389 let mut span = tracer.build(span_builder);
390 span.end();
391
392 let exported_spans = exporter
394 .get_finished_spans()
395 .expect("Spans are expected to be exported.");
396 assert_eq!(exported_spans.len(), 1);
397 let span = &exported_spans[0];
398 assert_eq!(span.name, "span_name");
399 assert_eq!(span.links.len(), DEFAULT_MAX_LINKS_PER_SPAN as usize);
400 }
401
402 #[test]
403 fn exceed_span_events_limit() {
404 let exporter = InMemorySpanExporterBuilder::new().build();
406 let provider = SdkTracerProvider::builder()
407 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
408 .build();
409
410 let tracer = provider.tracer("test_tracer");
412
413 let mut events = Vec::new();
414 for _i in 0..(DEFAULT_MAX_EVENT_PER_SPAN * 2) {
415 events.push(Event::with_name("test event"))
416 }
417
418 let span_builder = SpanBuilder::from_name("span_name").with_events(events);
420 let mut span = tracer.build(span_builder);
421
422 span.add_event("test event again, after span builder", Vec::new());
424 span.add_event("test event once again, after span builder", Vec::new());
425 span.end();
426
427 let exported_spans = exporter
429 .get_finished_spans()
430 .expect("Spans are expected to be exported.");
431 assert_eq!(exported_spans.len(), 1);
432 let span = &exported_spans[0];
433 assert_eq!(span.name, "span_name");
434 assert_eq!(span.events.len(), DEFAULT_MAX_EVENT_PER_SPAN as usize);
435 assert_eq!(span.events.dropped_count, DEFAULT_MAX_EVENT_PER_SPAN + 2);
436 }
437
438 #[test]
439 fn trace_state_for_dropped_sampler() {
440 let exporter = InMemorySpanExporterBuilder::new().build();
441 let provider = SdkTracerProvider::builder()
442 .with_sampler(Sampler::AlwaysOff)
443 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
444 .build();
445
446 let tracer = provider.tracer("test");
447 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
448
449 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
450 TraceId::from(10000),
451 SpanId::from(20),
452 TraceFlags::SAMPLED,
453 true,
454 trace_state.clone(),
455 )));
456
457 let span = tracer.start_with_context("span", &parent_context);
458 assert_eq!(
459 span.span_context().trace_state().get("foo"),
460 trace_state.get("foo")
461 )
462 }
463
464 #[derive(Clone, Debug, Default)]
465 struct TestRecordOnlySampler {}
466
467 impl ShouldSample for TestRecordOnlySampler {
468 fn should_sample(
469 &self,
470 parent_context: Option<&Context>,
471 _trace_id: TraceId,
472 _name: &str,
473 _span_kind: &SpanKind,
474 _attributes: &[KeyValue],
475 _links: &[Link],
476 ) -> SamplingResult {
477 let trace_state = parent_context
478 .unwrap()
479 .span()
480 .span_context()
481 .trace_state()
482 .clone();
483 SamplingResult {
484 decision: SamplingDecision::RecordOnly,
485 attributes: vec![KeyValue::new("record_only_key", "record_only_value")],
486 trace_state,
487 }
488 }
489 }
490
491 #[test]
492 fn trace_state_for_record_only_sampler() {
493 let exporter = InMemorySpanExporterBuilder::new().build();
494 let provider = SdkTracerProvider::builder()
495 .with_sampler(TestRecordOnlySampler::default())
496 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
497 .build();
498
499 let tracer = provider.tracer("test");
500 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
501
502 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
503 TraceId::from(10000),
504 SpanId::from(20),
505 TraceFlags::SAMPLED,
506 true,
507 trace_state.clone(),
508 )));
509
510 let span = tracer.build_with_context(
511 SpanBuilder::from_name("span")
512 .with_attributes(vec![KeyValue::new("extra_attr_key", "extra_attr_value")]),
513 &parent_context,
514 );
515 assert!(!span.span_context().trace_flags().is_sampled());
516 assert_eq!(
517 span.exported_data().unwrap().attributes,
518 vec![
519 KeyValue::new("extra_attr_key", "extra_attr_value"),
520 KeyValue::new("record_only_key", "record_only_value")
521 ]
522 );
523 assert_eq!(span.span_context().trace_state().get("foo"), Some("bar"));
524 }
525
526 #[test]
527 fn tracer_attributes() {
528 let provider = SdkTracerProvider::builder().build();
529 let scope = InstrumentationScope::builder("basic")
530 .with_attributes(vec![KeyValue::new("test_k", "test_v")])
531 .build();
532
533 let tracer = provider.tracer_with_scope(scope);
534 let instrumentation_scope = tracer.instrumentation_scope();
535 assert!(instrumentation_scope
536 .attributes()
537 .eq(&[KeyValue::new("test_k", "test_v")]));
538 }
539
540 #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
541 async fn empty_tracer_name_retained() {
542 async fn tracer_name_retained_helper(
543 tracer: super::SdkTracer,
544 provider: SdkTracerProvider,
545 exporter: InMemorySpanExporter,
546 ) {
547 tracer.start("my_span").end();
549
550 assert!(provider.force_flush().is_ok());
552
553 let finished_spans = exporter
555 .get_finished_spans()
556 .expect("spans are expected to be exported.");
557 assert_eq!(finished_spans.len(), 1, "There should be a single span");
558
559 let tracer_name = finished_spans[0].instrumentation_scope.name();
560 assert_eq!(tracer_name, "", "The tracer name should be an empty string");
561
562 exporter.reset();
563 }
564
565 let exporter = InMemorySpanExporter::default();
566 let span_processor = SimpleSpanProcessor::new(exporter.clone());
567 let tracer_provider = SdkTracerProvider::builder()
568 .with_span_processor(span_processor)
569 .build();
570
571 let tracer1 = tracer_provider.tracer("");
573 tracer_name_retained_helper(tracer1, tracer_provider.clone(), exporter.clone()).await;
574
575 let tracer_scope = InstrumentationScope::builder("").build();
576 let tracer2 = tracer_provider.tracer_with_scope(tracer_scope);
577 tracer_name_retained_helper(tracer2, tracer_provider, exporter).await;
578 }
579
580 #[test]
581 fn trace_suppression() {
582 let exporter = InMemorySpanExporter::default();
584 let span_processor = SimpleSpanProcessor::new(exporter.clone());
585 let tracer_provider = SdkTracerProvider::builder()
586 .with_span_processor(span_processor)
587 .build();
588
589 let tracer = tracer_provider.tracer("test");
591 {
592 let _suppressed_context = Context::enter_telemetry_suppressed_scope();
593 let _span = tracer.span_builder("span_name").start(&tracer);
595 }
596
597 let finished_spans = exporter.get_finished_spans().expect("this should not fail");
599 assert_eq!(
600 finished_spans.len(),
601 0,
602 "There should be a no spans as span emission is done inside a suppressed context"
603 );
604 }
605}