1use crate::sdk::trace::SpanLimits;
11use crate::sdk::{
12 trace::{
13 provider::{TracerProvider, TracerProviderInner},
14 span::{Span, SpanData},
15 Config, EvictedHashMap, EvictedQueue, SamplingDecision, SamplingResult,
16 },
17 InstrumentationLibrary,
18};
19use crate::trace::{
20 Link, SpanBuilder, SpanContext, SpanId, SpanKind, StatusCode, TraceContextExt, TraceFlags,
21 TraceId, TraceState,
22};
23use crate::{Context, KeyValue};
24use std::borrow::Cow;
25use std::fmt;
26use std::sync::Weak;
27
28#[derive(Clone)]
30pub struct Tracer {
31 instrumentation_lib: InstrumentationLibrary,
32 provider: Weak<TracerProviderInner>,
33}
34
35impl fmt::Debug for Tracer {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.debug_struct("Tracer")
40 .field("name", &self.instrumentation_lib.name)
41 .field("version", &self.instrumentation_lib.version)
42 .finish()
43 }
44}
45
46impl Tracer {
47 pub(crate) fn new(
49 instrumentation_lib: InstrumentationLibrary,
50 provider: Weak<TracerProviderInner>,
51 ) -> Self {
52 Tracer {
53 instrumentation_lib,
54 provider,
55 }
56 }
57
58 pub fn provider(&self) -> Option<TracerProvider> {
60 self.provider.upgrade().map(TracerProvider::new)
61 }
62
63 pub fn instrumentation_library(&self) -> &InstrumentationLibrary {
65 &self.instrumentation_lib
66 }
67
68 #[allow(clippy::too_many_arguments)]
70 fn make_sampling_decision(
71 &self,
72 parent_cx: &Context,
73 trace_id: TraceId,
74 name: &str,
75 span_kind: &SpanKind,
76 attributes: &[KeyValue],
77 links: &[Link],
78 config: &Config,
79 instrumentation_library: &InstrumentationLibrary,
80 ) -> Option<(TraceFlags, Vec<KeyValue>, TraceState)> {
81 let sampling_result = config.sampler.should_sample(
82 Some(parent_cx),
83 trace_id,
84 name,
85 span_kind,
86 attributes,
87 links,
88 instrumentation_library,
89 );
90
91 self.process_sampling_result(sampling_result, parent_cx)
92 }
93
94 fn process_sampling_result(
95 &self,
96 sampling_result: SamplingResult,
97 parent_cx: &Context,
98 ) -> Option<(TraceFlags, Vec<KeyValue>, TraceState)> {
99 match sampling_result {
100 SamplingResult {
101 decision: SamplingDecision::Drop,
102 ..
103 } => None,
104 SamplingResult {
105 decision: SamplingDecision::RecordOnly,
106 attributes,
107 trace_state,
108 } => {
109 let trace_flags = parent_cx.span().span_context().trace_flags();
110 Some((trace_flags.with_sampled(false), attributes, trace_state))
111 }
112 SamplingResult {
113 decision: SamplingDecision::RecordAndSample,
114 attributes,
115 trace_state,
116 } => {
117 let trace_flags = parent_cx.span().span_context().trace_flags();
118 Some((trace_flags.with_sampled(true), attributes, trace_state))
119 }
120 }
121 }
122}
123
124impl crate::trace::Tracer for Tracer {
125 type Span = Span;
127
128 fn start_with_context<T>(&self, name: T, parent_cx: &Context) -> Self::Span
136 where
137 T: Into<Cow<'static, str>>,
138 {
139 self.build_with_context(SpanBuilder::from_name(name), parent_cx)
140 }
141
142 fn span_builder<T>(&self, name: T) -> SpanBuilder
146 where
147 T: Into<Cow<'static, str>>,
148 {
149 SpanBuilder::from_name(name)
150 }
151
152 fn build_with_context(&self, mut builder: SpanBuilder, parent_cx: &Context) -> Self::Span {
160 let provider = self.provider();
161 if provider.is_none() {
162 return Span::new(
163 SpanContext::empty_context(),
164 None,
165 self.clone(),
166 SpanLimits::default(),
167 );
168 }
169
170 let provider = provider.unwrap();
171 let config = provider.config();
172 let span_limits = config.span_limits;
173 let span_id = builder
174 .span_id
175 .take()
176 .unwrap_or_else(|| config.id_generator.new_span_id());
177 let span_kind = builder.span_kind.take().unwrap_or(SpanKind::Internal);
178 let mut attribute_options = builder.attributes.take().unwrap_or_default();
179 let mut link_options = builder.links.take();
180 let mut no_parent = true;
181 let mut remote_parent = false;
182 let mut parent_span_id = SpanId::INVALID;
183 let mut parent_trace_flags = TraceFlags::default();
184 let trace_id;
185
186 let parent_span = if parent_cx.has_active_span() {
187 Some(parent_cx.span())
188 } else {
189 None
190 };
191
192 if let Some(sc) = parent_span.as_ref().map(|parent| parent.span_context()) {
194 no_parent = false;
195 remote_parent = sc.is_remote();
196 parent_span_id = sc.span_id();
197 parent_trace_flags = sc.trace_flags();
198 trace_id = sc.trace_id();
199 } else {
200 trace_id = builder
201 .trace_id
202 .unwrap_or_else(|| config.id_generator.new_trace_id());
203 };
204
205 let sampling_decision = if let Some(sampling_result) = builder.sampling_result.take() {
211 self.process_sampling_result(sampling_result, parent_cx)
212 } else if no_parent || remote_parent {
213 self.make_sampling_decision(
214 parent_cx,
215 trace_id,
216 &builder.name,
217 &span_kind,
218 &attribute_options,
219 link_options.as_deref().unwrap_or(&[]),
220 provider.config(),
221 &self.instrumentation_lib,
222 )
223 } else {
224 parent_span
226 .filter(|span| span.span_context().is_sampled())
227 .map(|span| {
228 (
229 parent_trace_flags,
230 Vec::new(),
231 span.span_context().trace_state().clone(),
232 )
233 })
234 };
235
236 let SpanBuilder {
237 name,
238 start_time,
239 end_time,
240 events,
241 status_code,
242 status_message,
243 ..
244 } = builder;
245
246 let mut span = if let Some((flags, mut extra_attrs, trace_state)) = sampling_decision {
248 if !extra_attrs.is_empty() {
249 attribute_options.append(&mut extra_attrs);
250 }
251 let mut attributes =
252 EvictedHashMap::new(span_limits.max_attributes_per_span, attribute_options.len());
253 for attribute in attribute_options {
254 attributes.insert(attribute);
255 }
256 let mut links = EvictedQueue::new(span_limits.max_links_per_span);
257 if let Some(link_options) = &mut link_options {
258 let link_attributes_limit = span_limits.max_attributes_per_link as usize;
259 for link in link_options.iter_mut() {
260 let dropped_attributes_count =
261 link.attributes.len().saturating_sub(link_attributes_limit);
262 link.attributes.truncate(link_attributes_limit);
263 link.dropped_attributes_count = dropped_attributes_count as u32;
264 }
265 links.append_vec(link_options);
266 }
267 let start_time = start_time.unwrap_or_else(crate::time::now);
268 let end_time = end_time.unwrap_or(start_time);
269 let mut events_queue = EvictedQueue::new(span_limits.max_events_per_span);
270 if let Some(mut events) = events {
271 let event_attributes_limit = span_limits.max_attributes_per_event as usize;
272 for event in events.iter_mut() {
273 let dropped_attributes_count = event
274 .attributes
275 .len()
276 .saturating_sub(event_attributes_limit);
277 event.attributes.truncate(event_attributes_limit);
278 event.dropped_attributes_count = dropped_attributes_count as u32;
279 }
280 events_queue.append_vec(&mut events);
281 }
282 let status_code = status_code.unwrap_or(StatusCode::Unset);
283 let status_message = status_message.unwrap_or(Cow::Borrowed(""));
284
285 let span_context = SpanContext::new(trace_id, span_id, flags, false, trace_state);
286 Span::new(
287 span_context,
288 Some(SpanData {
289 parent_span_id,
290 span_kind,
291 name,
292 start_time,
293 end_time,
294 attributes,
295 events: events_queue,
296 links,
297 status_code,
298 status_message,
299 }),
300 self.clone(),
301 span_limits,
302 )
303 } else {
304 let span_context = SpanContext::new(
305 trace_id,
306 span_id,
307 TraceFlags::default(),
308 false,
309 Default::default(),
310 );
311 Span::new(span_context, None, self.clone(), span_limits)
312 };
313
314 for processor in provider.span_processors() {
316 processor.on_start(&mut span, parent_cx)
317 }
318
319 span
320 }
321}
322
323#[cfg(all(test, feature = "testing", feature = "trace"))]
324mod tests {
325 use crate::{
326 sdk::{
327 self,
328 trace::{Config, Sampler, SamplingDecision, SamplingResult, ShouldSample},
329 InstrumentationLibrary,
330 },
331 testing::trace::TestSpan,
332 trace::{
333 Link, Span, SpanContext, SpanId, SpanKind, TraceContextExt, TraceFlags, TraceId,
334 TraceState, Tracer, TracerProvider,
335 },
336 Context, KeyValue,
337 };
338
339 #[derive(Debug)]
340 struct TestSampler {}
341
342 impl ShouldSample for TestSampler {
343 fn should_sample(
344 &self,
345 parent_context: Option<&Context>,
346 _trace_id: TraceId,
347 _name: &str,
348 _span_kind: &SpanKind,
349 _attributes: &[KeyValue],
350 _links: &[Link],
351 _instrumentation_library: &InstrumentationLibrary,
352 ) -> SamplingResult {
353 let trace_state = parent_context
354 .unwrap()
355 .span()
356 .span_context()
357 .trace_state()
358 .clone();
359 SamplingResult {
360 decision: SamplingDecision::RecordAndSample,
361 attributes: Vec::new(),
362 trace_state: trace_state.insert("foo", "notbar").unwrap(),
363 }
364 }
365 }
366
367 #[test]
368 fn allow_sampler_to_change_trace_state() {
369 let sampler = TestSampler {};
371 let config = Config::default().with_sampler(sampler);
372 let tracer_provider = sdk::trace::TracerProvider::builder()
373 .with_config(config)
374 .build();
375 let tracer = tracer_provider.tracer("test");
376 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
377
378 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
379 TraceId::from_u128(128),
380 SpanId::from_u64(64),
381 TraceFlags::SAMPLED,
382 true,
383 trace_state,
384 )));
385
386 let span = tracer.start_with_context("foo", &parent_context);
388 let span_context = span.span_context();
389 let expected = span_context.trace_state();
390 assert_eq!(expected.get("foo"), Some("notbar"))
391 }
392
393 #[test]
394 fn drop_parent_based_children() {
395 let sampler = Sampler::ParentBased(Box::new(Sampler::AlwaysOn));
396 let config = Config::default().with_sampler(sampler);
397 let tracer_provider = sdk::trace::TracerProvider::builder()
398 .with_config(config)
399 .build();
400
401 let context = Context::current_with_span(TestSpan(SpanContext::empty_context()));
402 let tracer = tracer_provider.tracer("test");
403 let span = tracer.start_with_context("must_not_be_sampled", &context);
404
405 assert!(!span.span_context().is_sampled());
406 }
407
408 #[test]
409 fn uses_current_context_for_builders_if_unset() {
410 let sampler = Sampler::ParentBased(Box::new(Sampler::AlwaysOn));
411 let config = Config::default().with_sampler(sampler);
412 let tracer_provider = sdk::trace::TracerProvider::builder()
413 .with_config(config)
414 .build();
415 let tracer = tracer_provider.tracer("test");
416
417 let _attached = Context::current_with_span(TestSpan(SpanContext::empty_context())).attach();
418 let span = tracer.span_builder("must_not_be_sampled").start(&tracer);
419 assert!(!span.span_context().is_sampled());
420
421 let _attached = Context::current()
422 .with_remote_span_context(SpanContext::new(
423 TraceId::from_u128(1),
424 SpanId::from_u64(1),
425 TraceFlags::default(),
426 true,
427 Default::default(),
428 ))
429 .attach();
430 let span = tracer.span_builder("must_not_be_sampled").start(&tracer);
431
432 assert!(!span.span_context().is_sampled());
433 }
434}