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 let provider = self.provider();
182 if provider.is_shutdown() {
184 return Span::new(
185 SpanContext::empty_context(),
186 None,
187 self.clone(),
188 SpanLimits::default(),
189 );
190 }
191
192 let config = provider.config();
193 let span_id = builder
194 .span_id
195 .take()
196 .unwrap_or_else(|| config.id_generator.new_span_id());
197 let trace_id;
198 let mut psc = &SpanContext::empty_context();
199
200 let parent_span = if parent_cx.has_active_span() {
201 Some(parent_cx.span())
202 } else {
203 None
204 };
205
206 if let Some(sc) = parent_span.as_ref().map(|parent| parent.span_context()) {
208 trace_id = sc.trace_id();
209 psc = sc;
210 } else {
211 trace_id = builder
212 .trace_id
213 .unwrap_or_else(|| config.id_generator.new_trace_id());
214 };
215
216 let samplings_result = if let Some(sr) = builder.sampling_result.take() {
219 sr
220 } else {
221 config.sampler.should_sample(
222 Some(parent_cx),
223 trace_id,
224 &builder.name,
225 builder.span_kind.as_ref().unwrap_or(&SpanKind::Internal),
226 builder.attributes.as_ref().unwrap_or(&Vec::new()),
227 builder.links.as_deref().unwrap_or(&[]),
228 )
229 };
230
231 let trace_flags = parent_cx.span().span_context().trace_flags();
232 let trace_state = samplings_result.trace_state;
233 let span_limits = config.span_limits;
234 let mut span = match samplings_result.decision {
236 SamplingDecision::RecordAndSample => {
237 let sc = SpanContext::new(
238 trace_id,
239 span_id,
240 trace_flags.with_sampled(true),
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::RecordOnly => {
253 let sc = SpanContext::new(
254 trace_id,
255 span_id,
256 trace_flags.with_sampled(false),
257 false,
258 trace_state,
259 );
260 self.build_recording_span(
261 psc,
262 sc,
263 builder,
264 samplings_result.attributes,
265 span_limits,
266 )
267 }
268 SamplingDecision::Drop => {
269 let span_context =
270 SpanContext::new(trace_id, span_id, TraceFlags::default(), false, trace_state);
271 Span::new(span_context, None, self.clone(), span_limits)
272 }
273 };
274
275 for processor in provider.span_processors() {
277 processor.on_start(&mut span, parent_cx)
278 }
279
280 span
281 }
282}
283
284#[cfg(all(test, feature = "testing", feature = "trace"))]
285mod tests {
286 use crate::{
287 testing::trace::TestSpan,
288 trace::{Sampler, ShouldSample},
289 };
290 use opentelemetry::{
291 trace::{
292 Link, SamplingDecision, SamplingResult, Span, SpanContext, SpanId, SpanKind,
293 TraceContextExt, TraceFlags, TraceId, TraceState, Tracer, TracerProvider,
294 },
295 Context, KeyValue,
296 };
297
298 #[derive(Clone, Debug)]
299 struct TestSampler {}
300
301 impl ShouldSample for TestSampler {
302 fn should_sample(
303 &self,
304 parent_context: Option<&Context>,
305 _trace_id: TraceId,
306 _name: &str,
307 _span_kind: &SpanKind,
308 _attributes: &[KeyValue],
309 _links: &[Link],
310 ) -> SamplingResult {
311 let trace_state = parent_context
312 .unwrap()
313 .span()
314 .span_context()
315 .trace_state()
316 .clone();
317 SamplingResult {
318 decision: SamplingDecision::RecordAndSample,
319 attributes: Vec::new(),
320 trace_state: trace_state.insert("foo", "notbar").unwrap(),
321 }
322 }
323 }
324
325 #[test]
326 fn allow_sampler_to_change_trace_state() {
327 let sampler = TestSampler {};
329 let tracer_provider = crate::trace::SdkTracerProvider::builder()
330 .with_sampler(sampler)
331 .build();
332 let tracer = tracer_provider.tracer("test");
333 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
334
335 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
336 TraceId::from_u128(128),
337 SpanId::from_u64(64),
338 TraceFlags::SAMPLED,
339 true,
340 trace_state,
341 )));
342
343 let span = tracer.start_with_context("foo", &parent_context);
345 let span_context = span.span_context();
346 let expected = span_context.trace_state();
347 assert_eq!(expected.get("foo"), Some("notbar"))
348 }
349
350 #[test]
351 fn drop_parent_based_children() {
352 let sampler = Sampler::ParentBased(Box::new(Sampler::AlwaysOn));
353 let tracer_provider = crate::trace::SdkTracerProvider::builder()
354 .with_sampler(sampler)
355 .build();
356
357 let context = Context::current_with_span(TestSpan(SpanContext::empty_context()));
358 let tracer = tracer_provider.tracer("test");
359 let span = tracer.start_with_context("must_not_be_sampled", &context);
360
361 assert!(!span.span_context().is_sampled());
362 }
363
364 #[test]
365 fn uses_current_context_for_builders_if_unset() {
366 let sampler = Sampler::ParentBased(Box::new(Sampler::AlwaysOn));
367 let tracer_provider = crate::trace::SdkTracerProvider::builder()
368 .with_sampler(sampler)
369 .build();
370 let tracer = tracer_provider.tracer("test");
371
372 let _attached = Context::current_with_span(TestSpan(SpanContext::empty_context())).attach();
373 let span = tracer.span_builder("must_not_be_sampled").start(&tracer);
374 assert!(!span.span_context().is_sampled());
375
376 let context = Context::map_current(|cx| {
377 cx.with_remote_span_context(SpanContext::new(
378 TraceId::from_u128(1),
379 SpanId::from_u64(1),
380 TraceFlags::default(),
381 true,
382 Default::default(),
383 ))
384 });
385 let _attached = context.attach();
386 let span = tracer.span_builder("must_not_be_sampled").start(&tracer);
387
388 assert!(!span.span_context().is_sampled());
389 }
390}