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