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 = if parent_cx.has_active_span() {
193 Some(parent_cx.span())
194 } else {
195 None
196 };
197
198 if let Some(sc) = parent_span.as_ref().map(|parent| parent.span_context()) {
200 trace_id = sc.trace_id();
201 psc = sc;
202 } else {
203 trace_id = config.id_generator.new_trace_id();
204 };
205
206 let samplings_result = config.sampler.should_sample(
207 Some(parent_cx),
208 trace_id,
209 &builder.name,
210 builder.span_kind.as_ref().unwrap_or(&SpanKind::Internal),
211 builder.attributes.as_ref().unwrap_or(&Vec::new()),
212 builder.links.as_deref().unwrap_or(&[]),
213 );
214
215 let trace_flags = parent_cx.span().span_context().trace_flags();
216 let trace_state = samplings_result.trace_state;
217 let span_limits = config.span_limits;
218 let mut span = match samplings_result.decision {
220 SamplingDecision::RecordAndSample => {
221 let sc = SpanContext::new(
222 trace_id,
223 span_id,
224 trace_flags.with_sampled(true),
225 false,
226 trace_state,
227 );
228 self.build_recording_span(
229 psc,
230 sc,
231 builder,
232 samplings_result.attributes,
233 span_limits,
234 )
235 }
236 SamplingDecision::RecordOnly => {
237 let sc = SpanContext::new(
238 trace_id,
239 span_id,
240 trace_flags.with_sampled(false),
241 false,
242 trace_state,
243 );
244 self.build_recording_span(
245 psc,
246 sc,
247 builder,
248 samplings_result.attributes,
249 span_limits,
250 )
251 }
252 SamplingDecision::Drop => {
253 let span_context =
254 SpanContext::new(trace_id, span_id, TraceFlags::default(), false, trace_state);
255 Span::new(span_context, None, self.clone(), span_limits)
256 }
257 };
258
259 if span.is_recording() {
260 for processor in provider.span_processors() {
262 processor.on_start(&mut span, parent_cx)
263 }
264 }
265
266 span
267 }
268}
269
270#[cfg(all(test, feature = "testing", feature = "trace"))]
271mod tests {
272 use crate::{
273 testing::trace::TestSpan,
274 trace::{Sampler, SamplingDecision, SamplingResult, ShouldSample},
275 };
276 use opentelemetry::{
277 trace::{
278 Link, Span, SpanContext, SpanId, SpanKind, TraceContextExt, TraceFlags, TraceId,
279 TraceState, Tracer, TracerProvider,
280 },
281 Context, KeyValue,
282 };
283
284 #[derive(Clone, Debug)]
285 struct TestSampler {}
286
287 impl ShouldSample for TestSampler {
288 fn should_sample(
289 &self,
290 parent_context: Option<&Context>,
291 _trace_id: TraceId,
292 _name: &str,
293 _span_kind: &SpanKind,
294 _attributes: &[KeyValue],
295 _links: &[Link],
296 ) -> SamplingResult {
297 let trace_state = parent_context
298 .unwrap()
299 .span()
300 .span_context()
301 .trace_state()
302 .clone();
303 SamplingResult {
304 decision: SamplingDecision::RecordAndSample,
305 attributes: Vec::new(),
306 trace_state: trace_state.insert("foo", "notbar").unwrap(),
307 }
308 }
309 }
310
311 #[test]
312 fn allow_sampler_to_change_trace_state() {
313 let sampler = TestSampler {};
315 let tracer_provider = crate::trace::SdkTracerProvider::builder()
316 .with_sampler(sampler)
317 .build();
318 let tracer = tracer_provider.tracer("test");
319 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
320
321 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
322 TraceId::from(128),
323 SpanId::from(64),
324 TraceFlags::SAMPLED,
325 true,
326 trace_state,
327 )));
328
329 let span = tracer.start_with_context("foo", &parent_context);
331 let span_context = span.span_context();
332 let expected = span_context.trace_state();
333 assert_eq!(expected.get("foo"), Some("notbar"))
334 }
335
336 #[test]
337 fn allow_sampler_to_change_trace_state_boxed() {
338 let sampler: Box<dyn ShouldSample> = Box::new(TestSampler {});
340 let tracer_provider = crate::trace::SdkTracerProvider::builder()
341 .with_sampler(sampler)
342 .build();
343 let tracer = tracer_provider.tracer("test");
344 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
345
346 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
347 TraceId::from(128),
348 SpanId::from(64),
349 TraceFlags::SAMPLED,
350 true,
351 trace_state,
352 )));
353
354 let span = tracer.start_with_context("foo", &parent_context);
356 let span_context = span.span_context();
357 let expected = span_context.trace_state();
358 assert_eq!(expected.get("foo"), Some("notbar"))
359 }
360
361 #[test]
362 fn drop_parent_based_children() {
363 let sampler = Sampler::ParentBased(Box::new(Sampler::AlwaysOn));
364 let tracer_provider = crate::trace::SdkTracerProvider::builder()
365 .with_sampler(sampler)
366 .build();
367
368 let context = Context::current_with_span(TestSpan(SpanContext::empty_context()));
369 let tracer = tracer_provider.tracer("test");
370 let span = tracer.start_with_context("must_not_be_sampled", &context);
371
372 assert!(!span.span_context().is_sampled());
373 }
374
375 #[test]
376 fn uses_current_context_for_builders_if_unset() {
377 let sampler = Sampler::ParentBased(Box::new(Sampler::AlwaysOn));
378 let tracer_provider = crate::trace::SdkTracerProvider::builder()
379 .with_sampler(sampler)
380 .build();
381 let tracer = tracer_provider.tracer("test");
382
383 let _attached = Context::current_with_span(TestSpan(SpanContext::empty_context())).attach();
384 let span = tracer.span_builder("must_not_be_sampled").start(&tracer);
385 assert!(!span.span_context().is_sampled());
386
387 let context = Context::map_current(|cx| {
388 cx.with_remote_span_context(SpanContext::new(
389 TraceId::from(1),
390 SpanId::from(1),
391 TraceFlags::default(),
392 true,
393 Default::default(),
394 ))
395 });
396 let _attached = context.attach();
397 let span = tracer.span_builder("must_not_be_sampled").start(&tracer);
398
399 assert!(!span.span_context().is_sampled());
400 }
401
402 #[test]
403 fn in_span_with_context_uses_provided_context() {
404 use crate::trace::{InMemorySpanExporter, SimpleSpanProcessor};
405
406 let exporter = InMemorySpanExporter::default();
407 let tracer_provider = crate::trace::SdkTracerProvider::builder()
408 .with_sampler(Sampler::AlwaysOn)
409 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
410 .build();
411 let tracer = tracer_provider.tracer("test");
412
413 let parent_span = tracer.start("parent");
415 let parent_trace_id = parent_span.span_context().trace_id();
416 let parent_span_id = parent_span.span_context().span_id();
417 let parent_cx = Context::current_with_span(parent_span);
418
419 let mut child_trace_id = None;
421 let mut child_span_id = None;
422 let mut executed = false;
423
424 let returned_value = tracer.in_span_with_context("child-span", &parent_cx, |cx| {
425 let span = cx.span();
426 child_trace_id = Some(span.span_context().trace_id());
427 child_span_id = Some(span.span_context().span_id());
428 executed = true;
429 "test_result"
430 });
431
432 assert_eq!(child_trace_id, Some(parent_trace_id));
434 assert_ne!(child_span_id, Some(parent_span_id));
436 assert!(executed);
438 assert_eq!(returned_value, "test_result");
440
441 drop(parent_cx);
443
444 let spans = exporter.get_finished_spans().unwrap();
446 assert_eq!(spans.len(), 2);
447 let parent = spans.iter().find(|s| s.name == "parent").unwrap();
448 let child = spans.iter().find(|s| s.name == "child-span").unwrap();
449 assert_eq!(child.parent_span_id, parent.span_context.span_id());
450 assert_eq!(
451 child.span_context.trace_id(),
452 parent.span_context.trace_id()
453 );
454 }
455
456 #[test]
457 fn in_span_with_builder_uses_current_context() {
458 use crate::trace::{InMemorySpanExporter, SimpleSpanProcessor};
459
460 let exporter = InMemorySpanExporter::default();
461 let tracer_provider = crate::trace::SdkTracerProvider::builder()
462 .with_sampler(Sampler::AlwaysOn)
463 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
464 .build();
465 let tracer = tracer_provider.tracer("test");
466
467 let parent_span = tracer.start("parent");
469 let parent_trace_id = parent_span.span_context().trace_id();
470 let parent_span_id = parent_span.span_context().span_id();
471 let _attached = Context::current_with_span(parent_span).attach();
472
473 let mut child_trace_id = None;
475
476 tracer.in_span_with_builder(
477 tracer
478 .span_builder("child")
479 .with_kind(SpanKind::Client)
480 .with_attributes(vec![KeyValue::new("test_key", "test_value")]),
481 |cx| {
482 let span = cx.span();
483 child_trace_id = Some(span.span_context().trace_id());
484 },
485 );
486
487 assert_eq!(child_trace_id, Some(parent_trace_id));
489
490 drop(_attached);
492
493 let spans = exporter.get_finished_spans().unwrap();
495 assert_eq!(spans.len(), 2);
496 let child = spans.iter().find(|s| s.name == "child").unwrap();
497 assert_eq!(child.parent_span_id, parent_span_id);
498 assert_eq!(child.span_context.trace_id(), parent_trace_id);
499 }
500
501 #[test]
502 fn in_span_with_builder_and_context_uses_provided_context() {
503 use crate::trace::{InMemorySpanExporter, SimpleSpanProcessor};
504
505 let exporter = InMemorySpanExporter::default();
506 let tracer_provider = crate::trace::SdkTracerProvider::builder()
507 .with_sampler(Sampler::AlwaysOn)
508 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
509 .build();
510 let tracer = tracer_provider.tracer("test");
511
512 let parent_span = tracer.start("parent");
514 let parent_trace_id = parent_span.span_context().trace_id();
515 let parent_span_id = parent_span.span_context().span_id();
516 let parent_cx = Context::current_with_span(parent_span);
517
518 let mut child_trace_id = None;
520 let mut result = 0;
521
522 let returned_value = tracer.in_span_with_builder_and_context(
523 tracer
524 .span_builder("child")
525 .with_kind(SpanKind::Server)
526 .with_attributes(vec![
527 KeyValue::new("http.method", "GET"),
528 KeyValue::new("http.url", "/api/test"),
529 ]),
530 &parent_cx,
531 |cx| {
532 let span = cx.span();
533 child_trace_id = Some(span.span_context().trace_id());
534 result = 42;
535 result
536 },
537 );
538
539 assert_eq!(child_trace_id, Some(parent_trace_id));
541 assert_eq!(returned_value, 42);
543 assert_eq!(result, 42);
544
545 drop(parent_cx);
547
548 let spans = exporter.get_finished_spans().unwrap();
550 assert_eq!(spans.len(), 2);
551 let child = spans.iter().find(|s| s.name == "child").unwrap();
552 assert_eq!(child.parent_span_id, parent_span_id);
553 assert_eq!(child.span_context.trace_id(), parent_trace_id);
554 }
555
556 #[test]
557 fn in_span_with_builder_and_context_ignores_active_context() {
558 use crate::trace::{InMemorySpanExporter, SimpleSpanProcessor};
559
560 let exporter = InMemorySpanExporter::default();
561 let tracer_provider = crate::trace::SdkTracerProvider::builder()
562 .with_sampler(Sampler::AlwaysOn)
563 .with_span_processor(SimpleSpanProcessor::new(exporter.clone()))
564 .build();
565 let tracer = tracer_provider.tracer("test");
566
567 let active_span_context = SpanContext::new(
569 TraceId::from(1u128),
570 SpanId::from(1u64),
571 TraceFlags::SAMPLED,
572 true,
573 Default::default(),
574 );
575 let active_trace_id = active_span_context.trace_id();
576 let active_span_id = active_span_context.span_id();
577 let _attached = Context::current_with_span(TestSpan(active_span_context)).attach();
578
579 let provided_span_context = SpanContext::new(
581 TraceId::from(2u128),
582 SpanId::from(2u64),
583 TraceFlags::SAMPLED,
584 true,
585 Default::default(),
586 );
587 let provided_trace_id = provided_span_context.trace_id();
588 let provided_span_id = provided_span_context.span_id();
589 let provided_cx = Context::current_with_span(TestSpan(provided_span_context));
590
591 assert_ne!(active_trace_id, provided_trace_id);
593
594 let mut child_trace_id = None;
596
597 tracer.in_span_with_builder_and_context(
598 tracer.span_builder("child").with_kind(SpanKind::Internal),
599 &provided_cx,
600 |cx| {
601 let span = cx.span();
602 child_trace_id = Some(span.span_context().trace_id());
603 },
604 );
605
606 assert_eq!(child_trace_id, Some(provided_trace_id));
608 assert_ne!(child_trace_id, Some(active_trace_id));
609
610 let spans = exporter.get_finished_spans().unwrap();
612 assert_eq!(spans.len(), 1);
613 let child = &spans[0];
614 assert_eq!(child.name, "child");
615 assert_eq!(child.parent_span_id, provided_span_id);
616 assert_eq!(child.span_context.trace_id(), provided_trace_id);
617 assert_ne!(child.parent_span_id, active_span_id);
618 assert_ne!(child.span_context.trace_id(), active_trace_id);
619 }
620}