1use crate::trace::{
11 provider::SdkTracerProvider,
12 span::{Span, SpanData},
13 SamplingDecision, SpanEvents, SpanLimits, SpanLinks,
14};
15use opentelemetry::{
16 trace::{Span as _, SpanBuilder, SpanContext, SpanKind, Status, TraceContextExt, TraceFlags},
17 Context, InstrumentationScope, KeyValue,
18};
19use std::fmt;
20use std::sync::Arc;
21
22#[derive(Clone)]
24pub struct SdkTracer {
25 scope: Arc<InstrumentationScope>,
26 provider: SdkTracerProvider,
27}
28
29impl fmt::Debug for SdkTracer {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 f.debug_struct("Tracer")
34 .field("name", &self.scope.name())
35 .field("version", &self.scope.version())
36 .finish()
37 }
38}
39
40impl SdkTracer {
41 pub(crate) fn new(scope: InstrumentationScope, provider: SdkTracerProvider) -> Self {
43 SdkTracer {
44 scope: Arc::new(scope),
45 provider,
46 }
47 }
48
49 pub(crate) fn provider(&self) -> &SdkTracerProvider {
51 &self.provider
52 }
53
54 pub(crate) fn instrumentation_scope(&self) -> &InstrumentationScope {
56 &self.scope
57 }
58
59 fn build_recording_span(
60 &self,
61 psc: &SpanContext,
62 sc: SpanContext,
63 mut builder: SpanBuilder,
64 attrs: Vec<KeyValue>,
65 span_limits: SpanLimits,
66 ) -> Span {
67 let mut attribute_options = builder.attributes.take().unwrap_or_default();
68 for extra_attr in attrs {
69 attribute_options.push(extra_attr);
70 }
71 let span_attributes_limit = span_limits.max_attributes_per_span as usize;
72 let dropped_attributes_count = attribute_options
73 .len()
74 .saturating_sub(span_attributes_limit);
75 attribute_options.truncate(span_attributes_limit);
76 let dropped_attributes_count = dropped_attributes_count as u32;
77
78 let spans_links_limit = span_limits.max_links_per_span as usize;
88 let span_links: SpanLinks = if let Some(mut links) = builder.links.take() {
89 let dropped_count = links.len().saturating_sub(spans_links_limit);
90 links.truncate(spans_links_limit);
91 let link_attributes_limit = span_limits.max_attributes_per_link as usize;
92 for link in links.iter_mut() {
93 let dropped_attributes_count =
94 link.attributes.len().saturating_sub(link_attributes_limit);
95 link.attributes.truncate(link_attributes_limit);
96 link.dropped_attributes_count = dropped_attributes_count as u32;
97 }
98 SpanLinks {
99 links,
100 dropped_count: dropped_count as u32,
101 }
102 } else {
103 SpanLinks::default()
104 };
105
106 let SpanBuilder {
107 name,
108 start_time,
109 events,
110 ..
111 } = builder;
112
113 let start_time = start_time.unwrap_or_else(opentelemetry::time::now);
114 let spans_events_limit = span_limits.max_events_per_span as usize;
115 let span_events: SpanEvents = if let Some(mut events) = events {
116 let dropped_count = events.len().saturating_sub(spans_events_limit);
117 events.truncate(spans_events_limit);
118 let event_attributes_limit = span_limits.max_attributes_per_event as usize;
119 for event in events.iter_mut() {
120 let dropped_attributes_count = event
121 .attributes
122 .len()
123 .saturating_sub(event_attributes_limit);
124 event.attributes.truncate(event_attributes_limit);
125 event.dropped_attributes_count = dropped_attributes_count as u32;
126 }
127 SpanEvents {
128 events,
129 dropped_count: dropped_count as u32,
130 }
131 } else {
132 SpanEvents::default()
133 };
134 Span::new(
135 sc,
136 Some(SpanData {
137 parent_span_id: psc.span_id(),
138 parent_span_is_remote: psc.is_valid() && psc.is_remote(),
139 span_kind: builder.span_kind.take().unwrap_or(SpanKind::Internal),
140 name,
141 start_time,
142 end_time: start_time,
143 attributes: attribute_options,
144 dropped_attributes_count,
145 events: span_events,
146 links: span_links,
147 status: Status::default(),
148 }),
149 self.clone(),
150 span_limits,
151 )
152 }
153}
154
155impl opentelemetry::trace::Tracer for SdkTracer {
156 type Span = Span;
158
159 fn build_with_context(&self, builder: SpanBuilder, parent_cx: &Context) -> Self::Span {
167 if parent_cx.is_telemetry_suppressed() {
168 return Span::new(
169 SpanContext::empty_context(),
170 None,
171 self.clone(),
172 SpanLimits::default(),
173 );
174 }
175
176 let provider = self.provider();
177 if provider.is_shutdown() {
179 return Span::new(
180 SpanContext::empty_context(),
181 None,
182 self.clone(),
183 SpanLimits::default(),
184 );
185 }
186
187 let config = provider.config();
188 let span_id = config.id_generator.new_span_id();
189 let trace_id;
190 let mut psc = &SpanContext::empty_context();
191
192 let parent_span = Some(parent_cx.span()).filter(|span| span.span_context().is_valid());
196
197 if let Some(sc) = parent_span.as_ref().map(|parent| parent.span_context()) {
199 trace_id = sc.trace_id();
200 psc = sc;
201 } else {
202 trace_id = config.id_generator.new_trace_id();
203 };
204
205 let samplings_result = config.sampler.should_sample(
206 Some(parent_cx),
207 trace_id,
208 &builder.name,
209 builder.span_kind.as_ref().unwrap_or(&SpanKind::Internal),
210 builder.attributes.as_ref().unwrap_or(&Vec::new()),
211 builder.links.as_deref().unwrap_or(&[]),
212 );
213
214 let trace_flags = psc.trace_flags();
215 let trace_state = samplings_result.trace_state;
216 let span_limits = config.span_limits;
217 let mut span = match samplings_result.decision {
219 SamplingDecision::RecordAndSample => {
220 let sc = SpanContext::new(
221 trace_id,
222 span_id,
223 trace_flags.with_sampled(true),
224 false,
225 trace_state,
226 );
227 self.build_recording_span(
228 psc,
229 sc,
230 builder,
231 samplings_result.attributes,
232 span_limits,
233 )
234 }
235 SamplingDecision::RecordOnly => {
236 let sc = SpanContext::new(
237 trace_id,
238 span_id,
239 trace_flags.with_sampled(false),
240 false,
241 trace_state,
242 );
243 self.build_recording_span(
244 psc,
245 sc,
246 builder,
247 samplings_result.attributes,
248 span_limits,
249 )
250 }
251 SamplingDecision::Drop => {
252 let span_context =
253 SpanContext::new(trace_id, span_id, TraceFlags::default(), false, trace_state);
254 Span::new(span_context, None, self.clone(), span_limits)
255 }
256 };
257
258 if span.is_recording() {
259 for processor in provider.span_processors() {
261 processor.on_start(&mut span, parent_cx)
262 }
263 }
264
265 span
266 }
267}
268
269#[cfg(all(test, feature = "testing", feature = "trace"))]
270mod tests {
271 use crate::{
272 testing::trace::TestSpan,
273 trace::{Sampler, SamplingDecision, SamplingResult, ShouldSample},
274 };
275 use opentelemetry::{
276 trace::{
277 Link, Span, SpanContext, SpanId, SpanKind, TraceContextExt, TraceFlags, TraceId,
278 TraceState, Tracer, TracerProvider,
279 },
280 Context, KeyValue,
281 };
282
283 #[derive(Clone, Debug)]
284 struct TestSampler {}
285
286 impl ShouldSample for TestSampler {
287 fn should_sample(
288 &self,
289 parent_context: Option<&Context>,
290 _trace_id: TraceId,
291 _name: &str,
292 _span_kind: &SpanKind,
293 _attributes: &[KeyValue],
294 _links: &[Link],
295 ) -> SamplingResult {
296 let trace_state = parent_context
297 .unwrap()
298 .span()
299 .span_context()
300 .trace_state()
301 .clone();
302 SamplingResult {
303 decision: SamplingDecision::RecordAndSample,
304 attributes: Vec::new(),
305 trace_state: trace_state.insert("foo", "notbar").unwrap(),
306 }
307 }
308 }
309
310 #[test]
311 fn allow_sampler_to_change_trace_state() {
312 let sampler = TestSampler {};
314 let tracer_provider = crate::trace::SdkTracerProvider::builder()
315 .with_sampler(sampler)
316 .build();
317 let tracer = tracer_provider.tracer("test");
318 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
319
320 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
321 TraceId::from(128),
322 SpanId::from(64),
323 TraceFlags::SAMPLED,
324 true,
325 trace_state,
326 )));
327
328 let span = tracer.start_with_context("foo", &parent_context);
330 let span_context = span.span_context();
331 let expected = span_context.trace_state();
332 assert_eq!(expected.get("foo"), Some("notbar"))
333 }
334
335 #[test]
336 fn allow_sampler_to_change_trace_state_boxed() {
337 let sampler: Box<dyn ShouldSample> = Box::new(TestSampler {});
339 let tracer_provider = crate::trace::SdkTracerProvider::builder()
340 .with_sampler(sampler)
341 .build();
342 let tracer = tracer_provider.tracer("test");
343 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
344
345 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
346 TraceId::from(128),
347 SpanId::from(64),
348 TraceFlags::SAMPLED,
349 true,
350 trace_state,
351 )));
352
353 let span = tracer.start_with_context("foo", &parent_context);
355 let span_context = span.span_context();
356 let expected = span_context.trace_state();
357 assert_eq!(expected.get("foo"), Some("notbar"))
358 }
359
360 #[test]
361 fn drop_parent_based_children() {
362 let sampler = Sampler::ParentBased(Box::new(Sampler::AlwaysOn));
363 let tracer_provider = crate::trace::SdkTracerProvider::builder()
364 .with_sampler(sampler)
365 .build();
366
367 let context = Context::current_with_span(TestSpan(SpanContext::empty_context()));
368 let tracer = tracer_provider.tracer("test");
369 let span = tracer.start_with_context("must_not_be_sampled", &context);
370
371 assert!(!span.span_context().is_sampled());
372 }
373
374 #[test]
375 fn uses_current_context_for_builders_if_unset() {
376 let sampler = Sampler::ParentBased(Box::new(Sampler::AlwaysOn));
377 let tracer_provider = crate::trace::SdkTracerProvider::builder()
378 .with_sampler(sampler)
379 .build();
380 let tracer = tracer_provider.tracer("test");
381
382 let _attached = Context::current_with_span(TestSpan(SpanContext::empty_context())).attach();
383 let span = tracer.span_builder("must_not_be_sampled").start(&tracer);
384 assert!(!span.span_context().is_sampled());
385
386 let context = Context::map_current(|cx| {
387 cx.with_remote_span_context(SpanContext::new(
388 TraceId::from(1),
389 SpanId::from(1),
390 TraceFlags::default(),
391 true,
392 Default::default(),
393 ))
394 });
395 let _attached = context.attach();
396 let span = tracer.span_builder("must_not_be_sampled").start(&tracer);
397
398 assert!(!span.span_context().is_sampled());
399 }
400
401 #[test]
402 fn in_span_with_context_uses_provided_context() {
403 use crate::trace::{InMemorySpanExporter, SimpleSpanProcessor};
404
405 let exporter = InMemorySpanExporter::default();
406 let tracer_provider = crate::trace::SdkTracerProvider::builder()
407 .with_sampler(Sampler::AlwaysOn)
408 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
409 .build();
410 let tracer = tracer_provider.tracer("test");
411
412 let parent_span = tracer.start("parent");
414 let parent_trace_id = parent_span.span_context().trace_id();
415 let parent_span_id = parent_span.span_context().span_id();
416 let parent_cx = Context::current_with_span(parent_span);
417
418 let mut child_trace_id = None;
420 let mut child_span_id = None;
421 let mut executed = false;
422
423 let returned_value = tracer.in_span_with_context("child-span", &parent_cx, |cx| {
424 let span = cx.span();
425 child_trace_id = Some(span.span_context().trace_id());
426 child_span_id = Some(span.span_context().span_id());
427 executed = true;
428 "test_result"
429 });
430
431 assert_eq!(child_trace_id, Some(parent_trace_id));
433 assert_ne!(child_span_id, Some(parent_span_id));
435 assert!(executed);
437 assert_eq!(returned_value, "test_result");
439
440 drop(parent_cx);
442
443 let spans = exporter.get_finished_spans().unwrap();
445 assert_eq!(spans.len(), 2);
446 let parent = spans.iter().find(|s| s.name == "parent").unwrap();
447 let child = spans.iter().find(|s| s.name == "child-span").unwrap();
448 assert_eq!(child.parent_span_id, parent.span_context.span_id());
449 assert_eq!(
450 child.span_context.trace_id(),
451 parent.span_context.trace_id()
452 );
453 }
454
455 #[test]
456 fn in_span_with_builder_uses_current_context() {
457 use crate::trace::{InMemorySpanExporter, SimpleSpanProcessor};
458
459 let exporter = InMemorySpanExporter::default();
460 let tracer_provider = crate::trace::SdkTracerProvider::builder()
461 .with_sampler(Sampler::AlwaysOn)
462 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
463 .build();
464 let tracer = tracer_provider.tracer("test");
465
466 let parent_span = tracer.start("parent");
468 let parent_trace_id = parent_span.span_context().trace_id();
469 let parent_span_id = parent_span.span_context().span_id();
470 let _attached = Context::current_with_span(parent_span).attach();
471
472 let mut child_trace_id = None;
474
475 tracer.in_span_with_builder(
476 tracer
477 .span_builder("child")
478 .with_kind(SpanKind::Client)
479 .with_attributes(vec![KeyValue::new("test_key", "test_value")]),
480 |cx| {
481 let span = cx.span();
482 child_trace_id = Some(span.span_context().trace_id());
483 },
484 );
485
486 assert_eq!(child_trace_id, Some(parent_trace_id));
488
489 drop(_attached);
491
492 let spans = exporter.get_finished_spans().unwrap();
494 assert_eq!(spans.len(), 2);
495 let child = spans.iter().find(|s| s.name == "child").unwrap();
496 assert_eq!(child.parent_span_id, parent_span_id);
497 assert_eq!(child.span_context.trace_id(), parent_trace_id);
498 }
499
500 #[test]
501 fn in_span_with_builder_and_context_uses_provided_context() {
502 use crate::trace::{InMemorySpanExporter, SimpleSpanProcessor};
503
504 let exporter = InMemorySpanExporter::default();
505 let tracer_provider = crate::trace::SdkTracerProvider::builder()
506 .with_sampler(Sampler::AlwaysOn)
507 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
508 .build();
509 let tracer = tracer_provider.tracer("test");
510
511 let parent_span = tracer.start("parent");
513 let parent_trace_id = parent_span.span_context().trace_id();
514 let parent_span_id = parent_span.span_context().span_id();
515 let parent_cx = Context::current_with_span(parent_span);
516
517 let mut child_trace_id = None;
519 let mut result = 0;
520
521 let returned_value = tracer.in_span_with_builder_and_context(
522 tracer
523 .span_builder("child")
524 .with_kind(SpanKind::Server)
525 .with_attributes(vec![
526 KeyValue::new("http.method", "GET"),
527 KeyValue::new("http.url", "/api/test"),
528 ]),
529 &parent_cx,
530 |cx| {
531 let span = cx.span();
532 child_trace_id = Some(span.span_context().trace_id());
533 result = 42;
534 result
535 },
536 );
537
538 assert_eq!(child_trace_id, Some(parent_trace_id));
540 assert_eq!(returned_value, 42);
542 assert_eq!(result, 42);
543
544 drop(parent_cx);
546
547 let spans = exporter.get_finished_spans().unwrap();
549 assert_eq!(spans.len(), 2);
550 let child = spans.iter().find(|s| s.name == "child").unwrap();
551 assert_eq!(child.parent_span_id, parent_span_id);
552 assert_eq!(child.span_context.trace_id(), parent_trace_id);
553 }
554
555 #[test]
556 fn in_span_with_builder_and_context_ignores_active_context() {
557 use crate::trace::{InMemorySpanExporter, SimpleSpanProcessor};
558
559 let exporter = InMemorySpanExporter::default();
560 let tracer_provider = crate::trace::SdkTracerProvider::builder()
561 .with_sampler(Sampler::AlwaysOn)
562 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
563 .build();
564 let tracer = tracer_provider.tracer("test");
565
566 let active_span_context = SpanContext::new(
568 TraceId::from(1u128),
569 SpanId::from(1u64),
570 TraceFlags::SAMPLED,
571 true,
572 Default::default(),
573 );
574 let active_trace_id = active_span_context.trace_id();
575 let active_span_id = active_span_context.span_id();
576 let _attached = Context::current_with_span(TestSpan(active_span_context)).attach();
577
578 let provided_span_context = SpanContext::new(
580 TraceId::from(2u128),
581 SpanId::from(2u64),
582 TraceFlags::SAMPLED,
583 true,
584 Default::default(),
585 );
586 let provided_trace_id = provided_span_context.trace_id();
587 let provided_span_id = provided_span_context.span_id();
588 let provided_cx = Context::current_with_span(TestSpan(provided_span_context));
589
590 assert_ne!(active_trace_id, provided_trace_id);
592
593 let mut child_trace_id = None;
595
596 tracer.in_span_with_builder_and_context(
597 tracer.span_builder("child").with_kind(SpanKind::Internal),
598 &provided_cx,
599 |cx| {
600 let span = cx.span();
601 child_trace_id = Some(span.span_context().trace_id());
602 },
603 );
604
605 assert_eq!(child_trace_id, Some(provided_trace_id));
607 assert_ne!(child_trace_id, Some(active_trace_id));
608
609 let spans = exporter.get_finished_spans().unwrap();
611 assert_eq!(spans.len(), 1);
612 let child = &spans[0];
613 assert_eq!(child.name, "child");
614 assert_eq!(child.parent_span_id, provided_span_id);
615 assert_eq!(child.span_context.trace_id(), provided_trace_id);
616 assert_ne!(child.parent_span_id, active_span_id);
617 assert_ne!(child.span_context.trace_id(), active_trace_id);
618 }
619
620 #[test]
621 fn invalid_parent_starts_a_new_trace() {
622 use crate::trace::{InMemorySpanExporter, SimpleSpanProcessor};
623
624 let exporter = InMemorySpanExporter::default();
625 let tracer_provider = crate::trace::SdkTracerProvider::builder()
626 .with_sampler(Sampler::parent_based(Sampler::AlwaysOn))
628 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
629 .build();
630 let tracer = tracer_provider.tracer("test");
631
632 let parent_cx = Context::current_with_span(TestSpan(SpanContext::new(
635 TraceId::INVALID,
636 SpanId::from(7),
637 TraceFlags::SAMPLED,
638 true,
639 TraceState::default(),
640 )));
641
642 let span = tracer.build_with_context(tracer.span_builder("child"), &parent_cx);
643 let span_context = span.span_context().clone();
644 drop(span);
645
646 assert!(
647 span_context.trace_id() != TraceId::INVALID,
648 "a recorded span must not inherit an invalid parent's all-zero trace id"
649 );
650 assert!(span_context.is_valid());
651
652 let spans = exporter.get_finished_spans().unwrap();
653 assert_eq!(spans.len(), 1);
654 assert_eq!(spans[0].span_context.trace_id(), span_context.trace_id());
655 assert_eq!(
656 spans[0].parent_span_id,
657 SpanId::INVALID,
658 "an invalid parent must not be recorded as the parent"
659 );
660 }
661}