1use crate::trace::{
11 provider::SdkTracerProvider,
12 span::{Span, SpanData},
13 IdGenerator, ShouldSample, SpanEvents, SpanLimits, SpanLinks,
14};
15use opentelemetry::{
16 trace::{
17 SamplingDecision, Span as _, SpanBuilder, SpanContext, SpanKind, TraceContextExt,
18 TraceFlags,
19 },
20 Context, InstrumentationScope, KeyValue,
21};
22use std::fmt;
23
24#[derive(Clone)]
26pub struct SdkTracer {
27 scope: InstrumentationScope,
28 provider: SdkTracerProvider,
29}
30
31impl fmt::Debug for SdkTracer {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 f.debug_struct("Tracer")
36 .field("name", &self.scope.name())
37 .field("version", &self.scope.version())
38 .finish()
39 }
40}
41
42impl SdkTracer {
43 pub(crate) fn new(scope: InstrumentationScope, provider: SdkTracerProvider) -> Self {
45 SdkTracer { scope, provider }
46 }
47
48 pub(crate) fn provider(&self) -> &SdkTracerProvider {
50 &self.provider
51 }
52
53 pub(crate) fn instrumentation_scope(&self) -> &InstrumentationScope {
55 &self.scope
56 }
57
58 fn build_recording_span(
59 &self,
60 psc: &SpanContext,
61 sc: SpanContext,
62 mut builder: SpanBuilder,
63 attrs: Vec<KeyValue>,
64 span_limits: SpanLimits,
65 ) -> Span {
66 let mut attribute_options = builder.attributes.take().unwrap_or_default();
67 for extra_attr in attrs {
68 attribute_options.push(extra_attr);
69 }
70 let span_attributes_limit = span_limits.max_attributes_per_span as usize;
71 let dropped_attributes_count = attribute_options
72 .len()
73 .saturating_sub(span_attributes_limit);
74 attribute_options.truncate(span_attributes_limit);
75 let dropped_attributes_count = dropped_attributes_count as u32;
76
77 let spans_links_limit = span_limits.max_links_per_span as usize;
87 let span_links: SpanLinks = if let Some(mut links) = builder.links.take() {
88 let dropped_count = links.len().saturating_sub(spans_links_limit);
89 links.truncate(spans_links_limit);
90 let link_attributes_limit = span_limits.max_attributes_per_link as usize;
91 for link in links.iter_mut() {
92 let dropped_attributes_count =
93 link.attributes.len().saturating_sub(link_attributes_limit);
94 link.attributes.truncate(link_attributes_limit);
95 link.dropped_attributes_count = dropped_attributes_count as u32;
96 }
97 SpanLinks {
98 links,
99 dropped_count: dropped_count as u32,
100 }
101 } else {
102 SpanLinks::default()
103 };
104
105 let SpanBuilder {
106 name,
107 start_time,
108 end_time,
109 events,
110 status,
111 ..
112 } = builder;
113
114 let start_time = start_time.unwrap_or_else(opentelemetry::time::now);
115 let end_time = end_time.unwrap_or(start_time);
116 let spans_events_limit = span_limits.max_events_per_span as usize;
117 let span_events: SpanEvents = if let Some(mut events) = events {
118 let dropped_count = events.len().saturating_sub(spans_events_limit);
119 events.truncate(spans_events_limit);
120 let event_attributes_limit = span_limits.max_attributes_per_event as usize;
121 for event in events.iter_mut() {
122 let dropped_attributes_count = event
123 .attributes
124 .len()
125 .saturating_sub(event_attributes_limit);
126 event.attributes.truncate(event_attributes_limit);
127 event.dropped_attributes_count = dropped_attributes_count as u32;
128 }
129 SpanEvents {
130 events,
131 dropped_count: dropped_count as u32,
132 }
133 } else {
134 SpanEvents::default()
135 };
136 Span::new(
137 sc,
138 Some(SpanData {
139 parent_span_id: psc.span_id(),
140 parent_span_is_remote: psc.is_valid() && psc.is_remote(),
141 span_kind: builder.span_kind.take().unwrap_or(SpanKind::Internal),
142 name,
143 start_time,
144 end_time,
145 attributes: attribute_options,
146 dropped_attributes_count,
147 events: span_events,
148 links: span_links,
149 status,
150 }),
151 self.clone(),
152 span_limits,
153 )
154 }
155
156 #[doc(hidden)]
160 pub fn id_generator(&self) -> &dyn IdGenerator {
161 &*self.provider.config().id_generator
162 }
163
164 #[doc(hidden)]
168 pub fn should_sample(&self) -> &dyn ShouldSample {
169 &*self.provider.config().sampler
170 }
171}
172
173impl opentelemetry::trace::Tracer for SdkTracer {
174 type Span = Span;
176
177 fn build_with_context(&self, mut builder: SpanBuilder, parent_cx: &Context) -> Self::Span {
185 if parent_cx.is_telemetry_suppressed() {
186 return Span::new(
187 SpanContext::empty_context(),
188 None,
189 self.clone(),
190 SpanLimits::default(),
191 );
192 }
193
194 let provider = self.provider();
195 if provider.is_shutdown() {
197 return Span::new(
198 SpanContext::empty_context(),
199 None,
200 self.clone(),
201 SpanLimits::default(),
202 );
203 }
204
205 let config = provider.config();
206 let span_id = builder
207 .span_id
208 .take()
209 .unwrap_or_else(|| config.id_generator.new_span_id());
210 let trace_id;
211 let mut psc = &SpanContext::empty_context();
212
213 let parent_span = if parent_cx.has_active_span() {
214 Some(parent_cx.span())
215 } else {
216 None
217 };
218
219 if let Some(sc) = parent_span.as_ref().map(|parent| parent.span_context()) {
221 trace_id = sc.trace_id();
222 psc = sc;
223 } else {
224 trace_id = builder
225 .trace_id
226 .unwrap_or_else(|| config.id_generator.new_trace_id());
227 };
228
229 let samplings_result = if let Some(sr) = builder.sampling_result.take() {
232 sr
233 } else {
234 config.sampler.should_sample(
235 Some(parent_cx),
236 trace_id,
237 &builder.name,
238 builder.span_kind.as_ref().unwrap_or(&SpanKind::Internal),
239 builder.attributes.as_ref().unwrap_or(&Vec::new()),
240 builder.links.as_deref().unwrap_or(&[]),
241 )
242 };
243
244 let trace_flags = parent_cx.span().span_context().trace_flags();
245 let trace_state = samplings_result.trace_state;
246 let span_limits = config.span_limits;
247 let mut span = match samplings_result.decision {
249 SamplingDecision::RecordAndSample => {
250 let sc = SpanContext::new(
251 trace_id,
252 span_id,
253 trace_flags.with_sampled(true),
254 false,
255 trace_state,
256 );
257 self.build_recording_span(
258 psc,
259 sc,
260 builder,
261 samplings_result.attributes,
262 span_limits,
263 )
264 }
265 SamplingDecision::RecordOnly => {
266 let sc = SpanContext::new(
267 trace_id,
268 span_id,
269 trace_flags.with_sampled(false),
270 false,
271 trace_state,
272 );
273 self.build_recording_span(
274 psc,
275 sc,
276 builder,
277 samplings_result.attributes,
278 span_limits,
279 )
280 }
281 SamplingDecision::Drop => {
282 let span_context =
283 SpanContext::new(trace_id, span_id, TraceFlags::default(), false, trace_state);
284 Span::new(span_context, None, self.clone(), span_limits)
285 }
286 };
287
288 if span.is_recording() {
289 for processor in provider.span_processors() {
291 processor.on_start(&mut span, parent_cx)
292 }
293 }
294
295 span
296 }
297}
298
299#[cfg(all(test, feature = "testing", feature = "trace"))]
300mod tests {
301 use crate::{
302 testing::trace::TestSpan,
303 trace::{Sampler, ShouldSample},
304 };
305 use opentelemetry::{
306 trace::{
307 Link, SamplingDecision, SamplingResult, Span, SpanContext, SpanId, SpanKind,
308 TraceContextExt, TraceFlags, TraceId, TraceState, Tracer, TracerProvider,
309 },
310 Context, KeyValue,
311 };
312
313 #[derive(Clone, Debug)]
314 struct TestSampler {}
315
316 impl ShouldSample for TestSampler {
317 fn should_sample(
318 &self,
319 parent_context: Option<&Context>,
320 _trace_id: TraceId,
321 _name: &str,
322 _span_kind: &SpanKind,
323 _attributes: &[KeyValue],
324 _links: &[Link],
325 ) -> SamplingResult {
326 let trace_state = parent_context
327 .unwrap()
328 .span()
329 .span_context()
330 .trace_state()
331 .clone();
332 SamplingResult {
333 decision: SamplingDecision::RecordAndSample,
334 attributes: Vec::new(),
335 trace_state: trace_state.insert("foo", "notbar").unwrap(),
336 }
337 }
338 }
339
340 #[test]
341 fn allow_sampler_to_change_trace_state() {
342 let sampler = TestSampler {};
344 let tracer_provider = crate::trace::SdkTracerProvider::builder()
345 .with_sampler(sampler)
346 .build();
347 let tracer = tracer_provider.tracer("test");
348 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
349
350 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
351 TraceId::from(128),
352 SpanId::from(64),
353 TraceFlags::SAMPLED,
354 true,
355 trace_state,
356 )));
357
358 let span = tracer.start_with_context("foo", &parent_context);
360 let span_context = span.span_context();
361 let expected = span_context.trace_state();
362 assert_eq!(expected.get("foo"), Some("notbar"))
363 }
364
365 #[test]
366 fn drop_parent_based_children() {
367 let sampler = Sampler::ParentBased(Box::new(Sampler::AlwaysOn));
368 let tracer_provider = crate::trace::SdkTracerProvider::builder()
369 .with_sampler(sampler)
370 .build();
371
372 let context = Context::current_with_span(TestSpan(SpanContext::empty_context()));
373 let tracer = tracer_provider.tracer("test");
374 let span = tracer.start_with_context("must_not_be_sampled", &context);
375
376 assert!(!span.span_context().is_sampled());
377 }
378
379 #[test]
380 fn uses_current_context_for_builders_if_unset() {
381 let sampler = Sampler::ParentBased(Box::new(Sampler::AlwaysOn));
382 let tracer_provider = crate::trace::SdkTracerProvider::builder()
383 .with_sampler(sampler)
384 .build();
385 let tracer = tracer_provider.tracer("test");
386
387 let _attached = Context::current_with_span(TestSpan(SpanContext::empty_context())).attach();
388 let span = tracer.span_builder("must_not_be_sampled").start(&tracer);
389 assert!(!span.span_context().is_sampled());
390
391 let context = Context::map_current(|cx| {
392 cx.with_remote_span_context(SpanContext::new(
393 TraceId::from(1),
394 SpanId::from(1),
395 TraceFlags::default(),
396 true,
397 Default::default(),
398 ))
399 });
400 let _attached = context.attach();
401 let span = tracer.span_builder("must_not_be_sampled").start(&tracer);
402
403 assert!(!span.span_context().is_sampled());
404 }
405}