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