Skip to main content

tracing_opentelemetry/
layer.rs

1use crate::stack::IdValueStack;
2use crate::{OtelData, OtelDataLock, OtelDataState};
3pub use filtered::FilteredOpenTelemetryLayer;
4use opentelemetry::ContextGuard;
5use opentelemetry::{
6    trace::{self as otel, noop, Span, SpanBuilder, SpanKind, Status, TraceContextExt},
7    Context as OtelContext, Key, KeyValue, StringValue, Value,
8};
9use std::cell::{Cell, RefCell};
10use std::sync::Arc;
11use std::thread;
12#[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"))))]
13use std::time::Instant;
14use std::{any::TypeId, borrow::Cow};
15use std::{fmt, vec};
16use std::{marker, mem::take};
17use tracing_core::span::{self, Attributes, Id, Record};
18use tracing_core::{field, Event, Subscriber};
19#[cfg(feature = "tracing-log")]
20use tracing_log::NormalizeEvent;
21use tracing_subscriber::layer::Context;
22use tracing_subscriber::layer::Filter;
23use tracing_subscriber::registry::LookupSpan;
24use tracing_subscriber::Layer;
25#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
26use web_time::Instant;
27
28mod filtered;
29
30const SPAN_NAME_FIELD: &str = "otel.name";
31const SPAN_KIND_FIELD: &str = "otel.kind";
32const SPAN_STATUS_CODE_FIELD: &str = "otel.status_code";
33const SPAN_STATUS_DESCRIPTION_FIELD: &str = "otel.status_description";
34const SPAN_EVENT_COUNT_FIELD: &str = "otel.tracing_event_count";
35
36const EVENT_EXCEPTION_NAME: &str = "exception";
37const FIELD_EXCEPTION_MESSAGE: &str = "exception.message";
38const FIELD_EXCEPTION_STACKTRACE: &str = "exception.stacktrace";
39
40std::thread_local! {
41    static INSIDE_TRACING: Cell<bool> = const { Cell::new(false) };
42}
43
44fn prevent_reentrant_call<T>(f: impl FnOnce() -> T) -> T {
45    let old_value = INSIDE_TRACING.with(|inside| inside.replace(true));
46    #[cfg(all(test, __reentrant_tracing_test))]
47    tracing::info!("This should not deadlock...");
48    let result = f();
49    INSIDE_TRACING.with(|inside| inside.set(old_value));
50    result
51}
52
53/// An [OpenTelemetry] propagation layer for use in a project that uses
54/// [tracing].
55///
56/// [OpenTelemetry]: https://opentelemetry.io
57/// [tracing]: https://github.com/tokio-rs/tracing
58pub struct OpenTelemetryLayer<S, T> {
59    tracer: T,
60    location: bool,
61    tracked_inactivity: bool,
62    with_threads: bool,
63    with_level: bool,
64    with_target: bool,
65    context_activation: bool,
66    sem_conv_config: SemConvConfig,
67    with_context: WithContext,
68    _registry: marker::PhantomData<S>,
69}
70
71impl<S> Default for OpenTelemetryLayer<S, noop::NoopTracer>
72where
73    S: Subscriber + for<'span> LookupSpan<'span>,
74{
75    fn default() -> Self {
76        OpenTelemetryLayer::new(noop::NoopTracer::new())
77    }
78}
79
80/// Construct a layer to track spans via [OpenTelemetry].
81///
82/// It will convert the tracing spans to OpenTelemetry spans
83/// and tracing events which are in a span to events in the currently active OpenTelemetry span.
84/// Child-Parent links will be automatically translated as well.
85/// Follows-From links will also be generated, but only if the originating span has not been closed yet.
86///
87/// Various translations exist between semantic conventions of OpenTelemetry and `tracing`,
88/// such as including level information as fields, or mapping error fields to exceptions.
89/// See the various `layer().with_*` functions for configuration of these features.
90///
91/// [OpenTelemetry]: https://opentelemetry.io
92///
93/// # Examples
94///
95/// ```rust,no_run
96/// use tracing_subscriber::layer::SubscriberExt;
97/// use tracing_subscriber::Registry;
98///
99/// // Use the tracing subscriber `Registry`, or any other subscriber
100/// // that impls `LookupSpan`
101/// let subscriber = Registry::default().with(tracing_opentelemetry::layer());
102/// # drop(subscriber);
103/// ```
104pub fn layer<S>() -> OpenTelemetryLayer<S, noop::NoopTracer>
105where
106    S: Subscriber + for<'span> LookupSpan<'span>,
107{
108    OpenTelemetryLayer::default()
109}
110
111///
112/// This struct lets us call back into the layer from the [crate::OpenTelemetrySpanExt] methods,
113/// letting us access and mutate the underlying data on the layer side in the context of
114/// tokio-tracing's span operations.
115///
116/// The functions on this struct "remember" the types of the subscriber so that we
117/// can downcast to something aware of them without knowing those
118/// types at the callsite.
119///
120/// See https://github.com/tokio-rs/tracing/blob/4dad420ee1d4607bad79270c1520673fa6266a3d/tracing-error/src/layer.rs
121pub(crate) struct WithContext {
122    ///
123    /// Provides access to the OtelData associated with the given span ID.
124    ///
125    #[allow(clippy::type_complexity)]
126    pub(crate) with_context: fn(&tracing::Dispatch, &span::Id, f: &mut dyn FnMut(&mut OtelData)),
127
128    ///
129    /// Ensures the given SpanId has been activated - that is, created in the OTel side of things,
130    /// and had its SpanBuilder consumed - and then provides access to the OtelData associated with it.
131    ///
132    #[allow(clippy::type_complexity)]
133    pub(crate) with_activated_context:
134        fn(&tracing::Dispatch, &span::Id, f: &mut dyn FnMut(&mut OtelData)),
135
136    ///
137    /// Ensures the given SpanId has been activated - that is, created in the OTel side of things,
138    /// and had its SpanBuilder consumed - and then provides access to the OTel Context associated with it.
139    ///
140    #[allow(clippy::type_complexity)]
141    pub(crate) with_activated_otel_context:
142        fn(&tracing::Dispatch, &span::Id, f: &mut dyn FnMut(&OtelContext)),
143}
144
145impl WithContext {
146    ///
147    /// Return the OtelData associated with the given spanId.
148    ///
149    pub(crate) fn with_context(
150        &self,
151        dispatch: &tracing::Dispatch,
152        id: &span::Id,
153        mut f: impl FnMut(&mut OtelData),
154    ) {
155        (self.with_context)(dispatch, id, &mut f)
156    }
157
158    ///
159    /// If the span associated with the given SpanId has not yet been
160    /// built, build it, consuming the span ID.
161    ///
162    /// Optionally performs additional operations on the OtelData after building.
163    ///
164    pub(crate) fn with_activated_context(
165        &self,
166        dispatch: &tracing::Dispatch,
167        id: &span::Id,
168        mut f: impl FnMut(&mut OtelData),
169    ) {
170        (self.with_activated_context)(dispatch, id, &mut f)
171    }
172
173    ///
174    /// Ensures the given SpanId has been activated - that is, created in the OTel side of things,
175    /// and had its SpanBuilder consumed - and then provides access to the OtelData associated with it.
176    ///
177    #[allow(clippy::type_complexity)]
178    pub(crate) fn with_activated_otel_context(
179        &self,
180        dispatch: &tracing::Dispatch,
181        id: &span::Id,
182        mut f: impl FnMut(&OtelContext),
183    ) {
184        (self.with_activated_otel_context)(dispatch, id, &mut f)
185    }
186}
187
188fn str_to_span_kind(s: &str) -> Option<otel::SpanKind> {
189    match s {
190        s if s.eq_ignore_ascii_case("server") => Some(otel::SpanKind::Server),
191        s if s.eq_ignore_ascii_case("client") => Some(otel::SpanKind::Client),
192        s if s.eq_ignore_ascii_case("producer") => Some(otel::SpanKind::Producer),
193        s if s.eq_ignore_ascii_case("consumer") => Some(otel::SpanKind::Consumer),
194        s if s.eq_ignore_ascii_case("internal") => Some(otel::SpanKind::Internal),
195        _ => None,
196    }
197}
198
199fn str_to_status(s: &str) -> otel::Status {
200    match s {
201        s if s.eq_ignore_ascii_case("ok") => otel::Status::Ok,
202        s if s.eq_ignore_ascii_case("error") => otel::Status::error(""),
203        _ => otel::Status::Unset,
204    }
205}
206
207#[derive(Default)]
208struct SpanBuilderUpdates {
209    name: Option<Cow<'static, str>>,
210    span_kind: Option<SpanKind>,
211    status: Option<Status>,
212    attributes: Option<Vec<KeyValue>>,
213}
214
215impl SpanBuilderUpdates {
216    fn update(self, span_builder: &mut SpanBuilder, s: &mut Status) {
217        let Self {
218            name,
219            span_kind,
220            status,
221            attributes,
222        } = self;
223
224        if let Some(name) = name {
225            span_builder.name = name;
226        }
227        if let Some(span_kind) = span_kind {
228            span_builder.span_kind = Some(span_kind);
229        }
230        if let Some(status) = status {
231            *s = status;
232        }
233        if let Some(attributes) = attributes {
234            if let Some(builder_attributes) = &mut span_builder.attributes {
235                builder_attributes.extend(attributes);
236            } else {
237                span_builder.attributes = Some(attributes);
238            }
239        }
240    }
241
242    fn update_span(self, span: &opentelemetry::trace::SpanRef<'_>) {
243        let Self {
244            status, attributes, ..
245        } = self;
246
247        if let Some(status) = status {
248            span.set_status(status);
249        }
250        if let Some(attributes) = attributes {
251            span.set_attributes(attributes);
252        }
253    }
254}
255
256struct SpanEventVisitor<'a, 'b> {
257    event_builder: &'a mut otel::Event,
258    span_builder_updates: &'b mut Option<SpanBuilderUpdates>,
259    sem_conv_config: SemConvConfig,
260}
261
262impl field::Visit for SpanEventVisitor<'_, '_> {
263    /// Record events on the underlying OpenTelemetry [`Span`] from `bool` values.
264    ///
265    /// [`Span`]: opentelemetry::trace::Span
266    fn record_bool(&mut self, field: &field::Field, value: bool) {
267        match field.name() {
268            "message" => self.event_builder.name = value.to_string().into(),
269            // Skip fields that are actually log metadata that have already been handled
270            #[cfg(feature = "tracing-log")]
271            name if name.starts_with("log.") => (),
272            name => {
273                self.event_builder
274                    .attributes
275                    .push(KeyValue::new(name, value));
276            }
277        }
278    }
279
280    /// Record events on the underlying OpenTelemetry [`Span`] from `f64` values.
281    ///
282    /// [`Span`]: opentelemetry::trace::Span
283    fn record_f64(&mut self, field: &field::Field, value: f64) {
284        match field.name() {
285            "message" => self.event_builder.name = value.to_string().into(),
286            // Skip fields that are actually log metadata that have already been handled
287            #[cfg(feature = "tracing-log")]
288            name if name.starts_with("log.") => (),
289            name => {
290                self.event_builder
291                    .attributes
292                    .push(KeyValue::new(name, value));
293            }
294        }
295    }
296
297    /// Record events on the underlying OpenTelemetry [`Span`] from `i64` values.
298    ///
299    /// [`Span`]: opentelemetry::trace::Span
300    fn record_i64(&mut self, field: &field::Field, value: i64) {
301        match field.name() {
302            "message" => self.event_builder.name = value.to_string().into(),
303            // Skip fields that are actually log metadata that have already been handled
304            #[cfg(feature = "tracing-log")]
305            name if name.starts_with("log.") => (),
306            name => {
307                self.event_builder
308                    .attributes
309                    .push(KeyValue::new(name, value));
310            }
311        }
312    }
313
314    /// Record events on the underlying OpenTelemetry [`Span`] from `&str` values.
315    ///
316    /// [`Span`]: opentelemetry::trace::Span
317    fn record_str(&mut self, field: &field::Field, value: &str) {
318        match field.name() {
319            "message" => self.event_builder.name = value.to_string().into(),
320            // While tracing supports the error primitive, the instrumentation macro does not
321            // use the primitive and instead uses the debug or display primitive.
322            // In both cases, an event with an empty name and with an error attribute is created.
323            "error" if self.event_builder.name.is_empty() => {
324                if self.sem_conv_config.error_events_to_status {
325                    self.span_builder_updates
326                        .get_or_insert_with(SpanBuilderUpdates::default)
327                        .status
328                        .replace(otel::Status::error(format!("{value:?}")));
329                }
330                if self.sem_conv_config.error_events_to_exceptions {
331                    self.event_builder.name = EVENT_EXCEPTION_NAME.into();
332                    self.event_builder
333                        .attributes
334                        .push(KeyValue::new(FIELD_EXCEPTION_MESSAGE, format!("{value:?}")));
335                } else {
336                    self.event_builder
337                        .attributes
338                        .push(KeyValue::new("error", format!("{value:?}")));
339                }
340            }
341            // Skip fields that are actually log metadata that have already been handled
342            #[cfg(feature = "tracing-log")]
343            name if name.starts_with("log.") => (),
344            name => {
345                self.event_builder
346                    .attributes
347                    .push(KeyValue::new(name, value.to_string()));
348            }
349        }
350    }
351
352    /// Record events on the underlying OpenTelemetry [`Span`] from values that
353    /// implement Debug.
354    ///
355    /// [`Span`]: opentelemetry::trace::Span
356    fn record_debug(&mut self, field: &field::Field, value: &dyn fmt::Debug) {
357        match field.name() {
358            "message" => self.event_builder.name = format!("{value:?}").into(),
359            // While tracing supports the error primitive, the instrumentation macro does not
360            // use the primitive and instead uses the debug or display primitive.
361            // In both cases, an event with an empty name and with an error attribute is created.
362            "error" if self.event_builder.name.is_empty() => {
363                if self.sem_conv_config.error_events_to_status {
364                    self.span_builder_updates
365                        .get_or_insert_with(SpanBuilderUpdates::default)
366                        .status
367                        .replace(otel::Status::error(format!("{value:?}")));
368                }
369                if self.sem_conv_config.error_events_to_exceptions {
370                    self.event_builder.name = EVENT_EXCEPTION_NAME.into();
371                    self.event_builder
372                        .attributes
373                        .push(KeyValue::new(FIELD_EXCEPTION_MESSAGE, format!("{value:?}")));
374                } else {
375                    self.event_builder
376                        .attributes
377                        .push(KeyValue::new("error", format!("{value:?}")));
378                }
379            }
380            // Skip fields that are actually log metadata that have already been handled
381            #[cfg(feature = "tracing-log")]
382            name if name.starts_with("log.") => (),
383            name => {
384                self.event_builder
385                    .attributes
386                    .push(KeyValue::new(name, format!("{value:?}")));
387            }
388        }
389    }
390
391    /// Set attributes on the underlying OpenTelemetry [`Span`] using a [`std::error::Error`]'s
392    /// [`std::fmt::Display`] implementation. Also adds the `source` chain as an extra field
393    ///
394    /// [`Span`]: opentelemetry::trace::Span
395    fn record_error(
396        &mut self,
397        field: &tracing_core::Field,
398        value: &(dyn std::error::Error + 'static),
399    ) {
400        let mut chain: Vec<StringValue> = Vec::new();
401        let mut next_err = value.source();
402
403        while let Some(err) = next_err {
404            chain.push(err.to_string().into());
405            next_err = err.source();
406        }
407
408        let error_msg = value.to_string();
409
410        if self.sem_conv_config.error_fields_to_exceptions {
411            self.event_builder.attributes.push(KeyValue::new(
412                Key::new(FIELD_EXCEPTION_MESSAGE),
413                Value::String(StringValue::from(error_msg.clone())),
414            ));
415
416            // NOTE: This is actually not the stacktrace of the exception. This is
417            // the "source chain". It represents the heirarchy of errors from the
418            // app level to the lowest level such as IO. It does not represent all
419            // of the callsites in the code that led to the error happening.
420            // `std::error::Error::backtrace` is a nightly-only API and cannot be
421            // used here until the feature is stabilized.
422            self.event_builder.attributes.push(KeyValue::new(
423                Key::new(FIELD_EXCEPTION_STACKTRACE),
424                Value::Array(chain.clone().into()),
425            ));
426        }
427
428        if self.sem_conv_config.error_records_to_exceptions {
429            let attributes = self
430                .span_builder_updates
431                .get_or_insert_with(SpanBuilderUpdates::default)
432                .attributes
433                .get_or_insert_with(Vec::new);
434
435            attributes.push(KeyValue::new(
436                FIELD_EXCEPTION_MESSAGE,
437                Value::String(error_msg.clone().into()),
438            ));
439
440            // NOTE: This is actually not the stacktrace of the exception. This is
441            // the "source chain". It represents the heirarchy of errors from the
442            // app level to the lowest level such as IO. It does not represent all
443            // of the callsites in the code that led to the error happening.
444            // `std::error::Error::backtrace` is a nightly-only API and cannot be
445            // used here until the feature is stabilized.
446            attributes.push(KeyValue::new(
447                FIELD_EXCEPTION_STACKTRACE,
448                Value::Array(chain.clone().into()),
449            ));
450        }
451
452        self.event_builder.attributes.push(KeyValue::new(
453            Key::new(field.name()),
454            Value::String(StringValue::from(error_msg)),
455        ));
456        self.event_builder.attributes.push(KeyValue::new(
457            Key::new(format!("{}.chain", field.name())),
458            Value::Array(chain.into()),
459        ));
460    }
461}
462
463/// Control over the mapping between tracing fields/events and OpenTelemetry conventional status/exception fields
464#[derive(Clone, Copy)]
465struct SemConvConfig {
466    /// If an error value is recorded on an event/span, should the otel fields
467    /// be added
468    ///
469    /// Note that this uses tracings `record_error` which is only implemented for `(dyn Error + 'static)`.
470    error_fields_to_exceptions: bool,
471
472    /// If an error value is recorded on an event, should the otel fields be
473    /// added to the corresponding span
474    ///
475    /// Note that this uses tracings `record_error` which is only implemented for `(dyn Error + 'static)`.
476    error_records_to_exceptions: bool,
477
478    /// If a function is instrumented and returns a `Result`, should the error
479    /// value be propagated to the span status.
480    ///
481    /// Without this enabled, the span status will be "Error" with an empty description
482    /// when at least one error event is recorded in the span.
483    ///
484    /// Note: the instrument macro will emit an error event if the function returns the `Err` variant.
485    /// This is not affected by this setting. Disabling this will only affect the span status.
486    error_events_to_status: bool,
487
488    /// If an event with an empty name and a field named `error` is recorded,
489    /// should the event be rewritten to have the name `exception` and the field `exception.message`
490    ///
491    /// Follows the semantic conventions for exceptions.
492    ///
493    /// Note: the instrument macro will emit an error event if the function returns the `Err` variant.
494    /// This is not affected by this setting. Disabling this will only affect the created fields on the OTel span.
495    error_events_to_exceptions: bool,
496}
497
498struct SpanAttributeVisitor<'a> {
499    span_builder_updates: &'a mut SpanBuilderUpdates,
500    sem_conv_config: SemConvConfig,
501}
502
503impl SpanAttributeVisitor<'_> {
504    fn record(&mut self, attribute: KeyValue) {
505        self.span_builder_updates
506            .attributes
507            .get_or_insert_with(Vec::new)
508            .push(KeyValue::new(attribute.key, attribute.value));
509    }
510}
511
512impl field::Visit for SpanAttributeVisitor<'_> {
513    /// Set attributes on the underlying OpenTelemetry [`Span`] from `bool` values.
514    ///
515    /// [`Span`]: opentelemetry::trace::Span
516    fn record_bool(&mut self, field: &field::Field, value: bool) {
517        self.record(KeyValue::new(field.name(), value));
518    }
519
520    /// Set attributes on the underlying OpenTelemetry [`Span`] from `f64` values.
521    ///
522    /// [`Span`]: opentelemetry::trace::Span
523    fn record_f64(&mut self, field: &field::Field, value: f64) {
524        self.record(KeyValue::new(field.name(), value));
525    }
526
527    /// Set attributes on the underlying OpenTelemetry [`Span`] from `i64` values.
528    ///
529    /// [`Span`]: opentelemetry::trace::Span
530    fn record_i64(&mut self, field: &field::Field, value: i64) {
531        self.record(KeyValue::new(field.name(), value));
532    }
533
534    /// Set attributes on the underlying OpenTelemetry [`Span`] from `&str` values.
535    ///
536    /// [`Span`]: opentelemetry::trace::Span
537    fn record_str(&mut self, field: &field::Field, value: &str) {
538        match field.name() {
539            SPAN_NAME_FIELD => self.span_builder_updates.name = Some(value.to_string().into()),
540            SPAN_KIND_FIELD => self.span_builder_updates.span_kind = str_to_span_kind(value),
541            SPAN_STATUS_CODE_FIELD => self.span_builder_updates.status = Some(str_to_status(value)),
542            SPAN_STATUS_DESCRIPTION_FIELD => {
543                self.span_builder_updates.status = Some(otel::Status::error(value.to_string()))
544            }
545            _ => self.record(KeyValue::new(field.name(), value.to_string())),
546        }
547    }
548
549    /// Set attributes on the underlying OpenTelemetry [`Span`] from values that
550    /// implement Debug.
551    ///
552    /// [`Span`]: opentelemetry::trace::Span
553    fn record_debug(&mut self, field: &field::Field, value: &dyn fmt::Debug) {
554        match field.name() {
555            SPAN_NAME_FIELD => self.span_builder_updates.name = Some(format!("{value:?}").into()),
556            SPAN_KIND_FIELD => {
557                self.span_builder_updates.span_kind = str_to_span_kind(&format!("{value:?}"))
558            }
559            SPAN_STATUS_CODE_FIELD => {
560                self.span_builder_updates.status = Some(str_to_status(&format!("{value:?}")))
561            }
562            SPAN_STATUS_DESCRIPTION_FIELD => {
563                self.span_builder_updates.status = Some(otel::Status::error(format!("{value:?}")))
564            }
565            _ => self.record(KeyValue::new(
566                Key::new(field.name()),
567                Value::String(format!("{value:?}").into()),
568            )),
569        }
570    }
571
572    /// Set attributes on the underlying OpenTelemetry [`Span`] using a [`std::error::Error`]'s
573    /// [`std::fmt::Display`] implementation. Also adds the `source` chain as an extra field
574    ///
575    /// [`Span`]: opentelemetry::trace::Span
576    fn record_error(
577        &mut self,
578        field: &tracing_core::Field,
579        value: &(dyn std::error::Error + 'static),
580    ) {
581        let mut chain: Vec<StringValue> = Vec::new();
582        let mut next_err = value.source();
583
584        while let Some(err) = next_err {
585            chain.push(err.to_string().into());
586            next_err = err.source();
587        }
588
589        let error_msg = value.to_string();
590
591        if self.sem_conv_config.error_fields_to_exceptions {
592            self.record(KeyValue::new(
593                Key::new(FIELD_EXCEPTION_MESSAGE),
594                Value::from(error_msg.clone()),
595            ));
596
597            // NOTE: This is actually not the stacktrace of the exception. This is
598            // the "source chain". It represents the heirarchy of errors from the
599            // app level to the lowest level such as IO. It does not represent all
600            // of the callsites in the code that led to the error happening.
601            // `std::error::Error::backtrace` is a nightly-only API and cannot be
602            // used here until the feature is stabilized.
603            self.record(KeyValue::new(
604                Key::new(FIELD_EXCEPTION_STACKTRACE),
605                Value::Array(chain.clone().into()),
606            ));
607        }
608
609        self.record(KeyValue::new(
610            Key::new(field.name()),
611            Value::String(error_msg.into()),
612        ));
613        self.record(KeyValue::new(
614            Key::new(format!("{}.chain", field.name())),
615            Value::Array(chain.into()),
616        ));
617    }
618}
619
620impl<S, T> OpenTelemetryLayer<S, T>
621where
622    S: Subscriber + for<'span> LookupSpan<'span>,
623    T: otel::Tracer + 'static,
624    T::Span: Send + Sync,
625{
626    /// Set the [`Tracer`] that this layer will use to produce and track
627    /// OpenTelemetry [`Span`]s.
628    ///
629    /// [`Tracer`]: opentelemetry::trace::Tracer
630    /// [`Span`]: opentelemetry::trace::Span
631    ///
632    /// # Examples
633    ///
634    /// ```no_run
635    /// use tracing_opentelemetry::OpenTelemetryLayer;
636    /// use tracing_subscriber::layer::SubscriberExt;
637    /// use opentelemetry::trace::TracerProvider as _;
638    /// use tracing_subscriber::Registry;
639    ///
640    /// // Create an OTLP pipeline exporter for a `trace_demo` service.
641    ///
642    /// let otlp_exporter = opentelemetry_otlp::SpanExporter::builder()
643    ///     .with_tonic()
644    ///     .build()
645    ///     .unwrap();
646    ///
647    /// let tracer = opentelemetry_sdk::trace::SdkTracerProvider::builder()
648    ///     .with_simple_exporter(otlp_exporter)
649    ///     .build()
650    ///     .tracer("trace_demo");
651    ///
652    /// // Create a layer with the configured tracer
653    /// let otel_layer = OpenTelemetryLayer::new(tracer);
654    ///
655    /// // Use the tracing subscriber `Registry`, or any other subscriber
656    /// // that impls `LookupSpan`
657    /// let subscriber = Registry::default().with(otel_layer);
658    /// # drop(subscriber);
659    /// ```
660    pub fn new(tracer: T) -> Self {
661        OpenTelemetryLayer {
662            tracer,
663            location: true,
664            tracked_inactivity: true,
665            with_threads: true,
666            with_level: false,
667            with_target: true,
668            context_activation: true,
669            sem_conv_config: SemConvConfig {
670                error_fields_to_exceptions: true,
671                error_records_to_exceptions: true,
672                error_events_to_exceptions: true,
673                error_events_to_status: true,
674            },
675            with_context: WithContext {
676                with_context: Self::get_context,
677                with_activated_context: Self::get_activated_context,
678                with_activated_otel_context: Self::get_activated_otel_context,
679            },
680            _registry: marker::PhantomData,
681        }
682    }
683
684    /// Set the [`Tracer`] that this layer will use to produce and track
685    /// OpenTelemetry [`Span`]s.
686    ///
687    /// [`Tracer`]: opentelemetry::trace::Tracer
688    /// [`Span`]: opentelemetry::trace::Span
689    ///
690    /// # Examples
691    ///
692    /// ```no_run
693    /// use tracing_subscriber::layer::SubscriberExt;
694    /// use tracing_subscriber::Registry;
695    /// use opentelemetry::trace::TracerProvider;
696    ///
697    /// // Create an OTLP pipeline exporter for a `trace_demo` service.
698    ///
699    /// let otlp_exporter = opentelemetry_otlp::SpanExporter::builder()
700    ///     .with_tonic()
701    ///     .build()
702    ///     .unwrap();
703    ///
704    /// let tracer = opentelemetry_sdk::trace::SdkTracerProvider::builder()
705    ///     .with_simple_exporter(otlp_exporter)
706    ///     .build()
707    ///     .tracer("trace_demo");
708    ///
709    /// // Create a layer with the configured tracer
710    /// let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer);
711    ///
712    /// // Use the tracing subscriber `Registry`, or any other subscriber
713    /// // that impls `LookupSpan`
714    /// let subscriber = Registry::default().with(otel_layer);
715    /// # drop(subscriber);
716    /// ```
717    pub fn with_tracer<Tracer>(self, tracer: Tracer) -> OpenTelemetryLayer<S, Tracer>
718    where
719        Tracer: otel::Tracer + 'static,
720        Tracer::Span: Send + Sync,
721    {
722        OpenTelemetryLayer {
723            tracer,
724            location: self.location,
725            tracked_inactivity: self.tracked_inactivity,
726            with_threads: self.with_threads,
727            with_level: self.with_level,
728            with_target: self.with_target,
729            context_activation: self.context_activation,
730            sem_conv_config: self.sem_conv_config,
731            with_context: WithContext {
732                with_context: OpenTelemetryLayer::<S, Tracer>::get_context,
733                with_activated_context: OpenTelemetryLayer::<S, Tracer>::get_activated_context,
734                with_activated_otel_context:
735                    OpenTelemetryLayer::<S, Tracer>::get_activated_otel_context,
736            },
737            _registry: self._registry,
738            // cannot use ``..self` here due to different generics
739        }
740    }
741
742    /// Sets whether or not span and event metadata should include OpenTelemetry
743    /// exception fields such as `exception.message` and `exception.backtrace`
744    /// when an `Error` value is recorded. If multiple error values are recorded
745    /// on the same span/event, only the most recently recorded error value will
746    /// show up under these fields.
747    ///
748    /// These attributes follow the [OpenTelemetry semantic conventions for
749    /// exceptions][conv].
750    ///
751    /// By default, these attributes are recorded.
752    /// Note that this only works for `(dyn Error + 'static)`.
753    /// See [Implementations on Foreign Types of tracing::Value][impls] or [`OpenTelemetryLayer::with_error_events_to_exceptions`]
754    ///
755    /// [conv]: https://github.com/open-telemetry/semantic-conventions/tree/main/docs/exceptions/
756    /// [impls]: https://docs.rs/tracing/0.1.37/tracing/trait.Value.html#foreign-impls
757    pub fn with_error_fields_to_exceptions(self, error_fields_to_exceptions: bool) -> Self {
758        Self {
759            sem_conv_config: SemConvConfig {
760                error_fields_to_exceptions,
761                ..self.sem_conv_config
762            },
763            ..self
764        }
765    }
766
767    /// Sets whether or not an event considered for exception mapping (see [`OpenTelemetryLayer::with_error_records_to_exceptions`])
768    /// should be propagated to the span status error description.
769    ///
770    /// By default, these events do set the span status error description.
771    pub fn with_error_events_to_status(self, error_events_to_status: bool) -> Self {
772        Self {
773            sem_conv_config: SemConvConfig {
774                error_events_to_status,
775                ..self.sem_conv_config
776            },
777            ..self
778        }
779    }
780
781    /// Sets whether or not a subset of events following the described schema are mapped to
782    /// events following the [OpenTelemetry semantic conventions for
783    /// exceptions][conv].
784    ///
785    /// * Only events without a message field (unnamed events) and at least one field with the name error
786    ///   are considered for mapping.
787    ///
788    /// By default, these events are mapped.
789    ///
790    /// [conv]: https://github.com/open-telemetry/semantic-conventions/tree/main/docs/exceptions/
791    pub fn with_error_events_to_exceptions(self, error_events_to_exceptions: bool) -> Self {
792        Self {
793            sem_conv_config: SemConvConfig {
794                error_events_to_exceptions,
795                ..self.sem_conv_config
796            },
797            ..self
798        }
799    }
800
801    /// Sets whether or not reporting an `Error` value on an event will
802    /// propagate the OpenTelemetry exception fields such as `exception.message`
803    /// and `exception.backtrace` to the corresponding span. You do not need to
804    /// enable `with_exception_fields` in order to enable this. If multiple
805    /// error values are recorded on the same span/event, only the most recently
806    /// recorded error value will show up under these fields.
807    ///
808    /// These attributes follow the [OpenTelemetry semantic conventions for
809    /// exceptions][conv].
810    ///
811    /// By default, these attributes are propagated to the span. Note that this only works for `(dyn Error + 'static)`.
812    /// See [Implementations on Foreign Types of tracing::Value][impls] or [`OpenTelemetryLayer::with_error_events_to_exceptions`]
813    ///
814    /// [conv]: https://github.com/open-telemetry/semantic-conventions/tree/main/docs/exceptions/
815    /// [impls]: https://docs.rs/tracing/0.1.37/tracing/trait.Value.html#foreign-impls
816    pub fn with_error_records_to_exceptions(self, error_records_to_exceptions: bool) -> Self {
817        Self {
818            sem_conv_config: SemConvConfig {
819                error_records_to_exceptions,
820                ..self.sem_conv_config
821            },
822            ..self
823        }
824    }
825
826    /// Sets whether or not span and event metadata should include OpenTelemetry
827    /// attributes with location information, such as the file, module and line number.
828    ///
829    /// These attributes follow the [OpenTelemetry semantic conventions for
830    /// source locations][conv].
831    ///
832    /// By default, locations are enabled.
833    ///
834    /// [conv]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/attributes.md#source-code-attributes/
835    pub fn with_location(self, location: bool) -> Self {
836        Self { location, ..self }
837    }
838
839    /// Sets whether or not spans metadata should include the _busy time_
840    /// (total time for which it was entered), and _idle time_ (total time
841    /// the span existed but was not entered).
842    ///
843    /// By default, inactivity tracking is enabled.
844    pub fn with_tracked_inactivity(self, tracked_inactivity: bool) -> Self {
845        Self {
846            tracked_inactivity,
847            ..self
848        }
849    }
850
851    /// Sets whether or not spans record additional attributes for the thread
852    /// name and thread ID of the thread they were created on, following the
853    /// [OpenTelemetry semantic conventions for threads][conv].
854    ///
855    /// By default, thread attributes are enabled.
856    ///
857    /// [conv]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/attributes.md#general-thread-attributes/
858    pub fn with_threads(self, threads: bool) -> Self {
859        Self {
860            with_threads: threads,
861            ..self
862        }
863    }
864
865    /// Sets whether or not span metadata should include the `tracing` verbosity level information as a `level` field.
866    ///
867    /// The level is always added to events, and based on [`OpenTelemetryLayer::with_error_events_to_status`]
868    /// error-level events will mark the span status as an error.
869    ///
870    /// By default, level information is disabled.
871    pub fn with_level(self, level: bool) -> Self {
872        Self {
873            with_level: level,
874            ..self
875        }
876    }
877
878    /// Sets whether or not span metadata should include an attribute with `target` from `tracing` spans.
879    ///
880    /// By default, the target attribute is enabled..
881    pub fn with_target(self, target: bool) -> Self {
882        Self {
883            with_target: target,
884            ..self
885        }
886    }
887
888    /// Sets whether or not an OpenTelemetry Context should be activated on span entry.
889    ///
890    /// When enabled, entering a span will activate its OpenTelemetry context, making it
891    /// available to other OpenTelemetry instrumentation. This allows for proper context
892    /// propagation across different instrumentation libraries.
893    ///
894    /// By default, context activation is enabled.
895    pub fn with_context_activation(self, context_activation: bool) -> Self {
896        Self {
897            context_activation,
898            ..self
899        }
900    }
901
902    /// Adds a filter for events that counts all events that came to the layer. See
903    /// [`FilteredOpenTelemetryLayer`] for more details.
904    ///
905    /// If you just want to filter the events out and you don't need to count how many happened, you
906    /// can use [`Layer::with_filter`] instead.
907    pub fn with_counting_event_filter<F: Filter<S>>(
908        self,
909        filter: F,
910    ) -> FilteredOpenTelemetryLayer<S, T, F> {
911        FilteredOpenTelemetryLayer::new(self, filter)
912    }
913
914    /// Retrieve the parent OpenTelemetry [`Context`] from the current tracing
915    /// [`span`] through the [`Registry`]. This [`Context`] links spans to their
916    /// parent for proper hierarchical visualization.
917    ///
918    /// [`Context`]: opentelemetry::Context
919    /// [`span`]: tracing::Span
920    /// [`Registry`]: tracing_subscriber::Registry
921    fn parent_context(&self, attrs: &Attributes<'_>, ctx: &Context<'_, S>) -> OtelContext {
922        if let Some(parent) = attrs.parent() {
923            // A span can have an _explicit_ parent that is NOT seen by this `Layer` (for which
924            // `Context::span` returns `None`. This happens if the parent span is filtered away
925            // from the layer by a per-layer filter. In that case, we fall-through to the `else`
926            // case, and consider this span a root span.
927            //
928            // This is likely rare, as most users who use explicit parents will configure their
929            // filters so that children and parents are both seen, but it's not guaranteed. Also,
930            // if users configure their filter with a `reload` filter, it's possible that a parent
931            // and child have different filters as they are created with a filter change
932            // in-between.
933            //
934            // In these case, we prefer to emit a smaller span tree instead of panicking.
935            if let Some(span) = ctx.span(parent) {
936                let extensions = span.extensions();
937                if let Some(otel_data) = extensions.get::<OtelDataLock>() {
938                    // If the parent span has a span builder the parent span should be started
939                    // so we get a proper context with the parent span.
940                    return self.with_started_cx(&mut otel_data.lock(), &|cx| cx.clone());
941                }
942            }
943        }
944
945        if attrs.is_contextual() {
946            if self.context_activation {
947                // If the span is contextual and we are using context activation,
948                // we should use the current OTel context
949                OtelContext::current()
950            } else {
951                // If the span is contextual and we are not using context activation,
952                // we should use the current tracing context
953                ctx.lookup_current()
954                    .and_then(|span| {
955                        let extensions = span.extensions();
956                        extensions
957                            .get::<OtelDataLock>()
958                            .map(|data| self.with_started_cx(&mut data.lock(), &|cx| cx.clone()))
959                    })
960                    .unwrap_or_else(OtelContext::current)
961            }
962        } else {
963            OtelContext::default()
964        }
965    }
966
967    /// Provides access to the OpenTelemetry data (`OtelData`) stored in a tracing span.
968    ///
969    /// This function retrieves the span from the subscriber's registry using the provided span ID,
970    /// and then applies the callback function `f` to the span's `OtelData` if present.
971    ///
972    /// # Parameters
973    /// * `dispatch` - A reference to the tracing dispatch, used to access the subscriber
974    /// * `id` - The ID of the span to look up
975    /// * `f` - A callback function that receives a mutable reference to the span's `OtelData`
976    ///   This callback is used to manipulate or extract information from the OpenTelemetry context
977    ///   associated with the tracing span
978    ///
979    fn get_context(dispatch: &tracing::Dispatch, id: &span::Id, f: &mut dyn FnMut(&mut OtelData)) {
980        let subscriber = dispatch
981            .downcast_ref::<S>()
982            .expect("subscriber should downcast to expected type; this is a bug!");
983        let span = subscriber
984            .span(id)
985            .expect("registry should have a span for the current ID");
986
987        let otel_data = span.extensions().get::<OtelDataLock>().cloned();
988        if let Some(otel_data) = otel_data {
989            f(&mut otel_data.lock());
990        }
991    }
992
993    /// Retrieves the OpenTelemetry data for a span and activates its context before calling
994    /// the provided function.
995    ///
996    /// This function retrieves the span from the subscriber's registry using the provided
997    /// span ID, activates the OTel `Context` in the span's `OtelData` if present, and then
998    /// applies the callback function `f` to the `OtelData`.
999    ///
1000    /// # Parameters
1001    ///
1002    /// * `dispatch` - The tracing dispatch to downcast and retrieve the span from
1003    /// * `id` - The span ID to look up in the registry
1004    /// * `f` - The closure to invoke with mutable access to the span's `OtelData`
1005    fn get_activated_context(
1006        dispatch: &tracing::Dispatch,
1007        id: &span::Id,
1008        f: &mut dyn FnMut(&mut OtelData),
1009    ) {
1010        let layer = dispatch
1011            .downcast_ref::<OpenTelemetryLayer<S, T>>()
1012            .expect("layer should downcast to expected type; this is a bug!");
1013
1014        let subscriber = dispatch
1015            .downcast_ref::<S>()
1016            .expect("subscriber should downcast to expected type; this is a bug!");
1017
1018        let span = subscriber
1019            .span(id)
1020            .expect("registry should have a span for the current ID");
1021
1022        let otel_data = span.extensions().get::<OtelDataLock>().cloned();
1023
1024        if let Some(otel_data) = otel_data {
1025            let mut otel_data = otel_data.lock();
1026            // Activate the context
1027            layer.start_cx(&mut otel_data);
1028            f(&mut otel_data);
1029        }
1030    }
1031
1032    /// Retrieves the activated OpenTelemetry context from a span's ID and passes it
1033    /// to the provided function.
1034    ///
1035    /// This method activates the context and extracts the current OTel `Context` from the
1036    /// `OtelData` state if present, and then applies the callback function `f` to a reference
1037    /// to the OTel `Context`.
1038    ///
1039    /// # Parameters
1040    ///
1041    /// * `dispatch` - The tracing dispatch to downcast to the `OpenTelemetryLayer`
1042    /// * `id` - The span ID to look up in the registry
1043    /// * `f` - The closure to invoke with a reference to the OTel `Context`
1044    fn get_activated_otel_context(
1045        dispatch: &tracing::Dispatch,
1046        span: &span::Id,
1047        f: &mut dyn FnMut(&OtelContext),
1048    ) {
1049        Self::get_activated_context(dispatch, span, &mut |otel_data: &mut OtelData| {
1050            if let OtelDataState::Context { current_cx } = &otel_data.state {
1051                f(current_cx)
1052            }
1053        });
1054    }
1055
1056    fn extra_span_attrs(&self) -> usize {
1057        let mut extra_attrs = 0;
1058        if self.location {
1059            extra_attrs += 3;
1060        }
1061        if self.with_threads {
1062            extra_attrs += 2;
1063        }
1064        if self.with_level {
1065            extra_attrs += 1;
1066        }
1067        if self.with_target {
1068            extra_attrs += 1;
1069        }
1070        extra_attrs
1071    }
1072
1073    ///
1074    /// Builds the OTel span associated with given OTel context, consuming the SpanBuilder within
1075    /// the context in the process.
1076    ///
1077    fn start_cx(&self, otel_data: &mut OtelData) {
1078        if let OtelDataState::Context { .. } = &otel_data.state {
1079            // If the context is already started, we do nothing.
1080        } else if let OtelDataState::Builder {
1081            builder,
1082            parent_cx,
1083            status,
1084        } = take(&mut otel_data.state)
1085        {
1086            // We purposefully disable all tracing inside this call. Whoever called this is holding
1087            // a lock on `OtelData` and this is not reentrant.
1088            let current_cx = prevent_reentrant_call(|| {
1089                let mut span = builder.start_with_context(&self.tracer, &parent_cx);
1090                span.set_status(status);
1091                parent_cx.with_span(span)
1092            });
1093
1094            otel_data.state = OtelDataState::Context { current_cx };
1095        }
1096    }
1097
1098    fn with_started_cx<U>(&self, otel_data: &mut OtelData, f: &dyn Fn(&OtelContext) -> U) -> U {
1099        self.start_cx(otel_data);
1100        match &otel_data.state {
1101            OtelDataState::Context { current_cx, .. } => prevent_reentrant_call(|| f(current_cx)),
1102            _ => panic!("OtelDataState should be a Context after starting it; this is a bug!"),
1103        }
1104    }
1105}
1106
1107thread_local! {
1108    static THREAD_ID: u64 = {
1109        // OpenTelemetry's semantic conventions require the thread ID to be
1110        // recorded as an integer, but `std::thread::ThreadId` does not expose
1111        // the integer value on stable, so we have to convert it to a `usize` by
1112        // parsing it. Since this requires allocating a `String`, store it in a
1113        // thread local so we only have to do this once.
1114        // TODO(eliza): once `std::thread::ThreadId::as_u64` is stabilized
1115        // (https://github.com/rust-lang/rust/issues/67939), just use that.
1116        thread_id_integer(thread::current().id())
1117    };
1118}
1119
1120thread_local! {
1121    static GUARD_STACK: RefCell<IdContextGuardStack> = RefCell::new(IdContextGuardStack::new());
1122}
1123
1124type IdContextGuardStack = IdValueStack<ContextGuard>;
1125
1126impl<S, T> Layer<S> for OpenTelemetryLayer<S, T>
1127where
1128    S: Subscriber + for<'span> LookupSpan<'span>,
1129    T: otel::Tracer + 'static,
1130    T::Span: Send + Sync,
1131{
1132    /// Creates an [OpenTelemetry `Span`] for the corresponding [tracing `Span`].
1133    ///
1134    /// [OpenTelemetry `Span`]: opentelemetry::trace::Span
1135    /// [tracing `Span`]: tracing::Span
1136    fn on_new_span(&self, attrs: &Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
1137        let span = ctx.span(id).expect("Span not found, this is a bug");
1138        let mut extensions = span.extensions_mut();
1139
1140        if self.tracked_inactivity && extensions.get_mut::<Timings>().is_none() {
1141            extensions.insert(Timings::new());
1142        }
1143
1144        let parent_cx = self.parent_context(attrs, &ctx);
1145        let mut builder = self
1146            .tracer
1147            .span_builder(attrs.metadata().name())
1148            .with_start_time(crate::time::now());
1149
1150        let builder_attrs = builder.attributes.get_or_insert(Vec::with_capacity(
1151            attrs.fields().len() + self.extra_span_attrs(),
1152        ));
1153
1154        if self.location {
1155            let meta = attrs.metadata();
1156
1157            if let Some(filename) = meta.file() {
1158                builder_attrs.push(KeyValue::new("code.file.path", filename));
1159            }
1160
1161            if let Some(module) = meta.module_path() {
1162                builder_attrs.push(KeyValue::new("code.module.name", module));
1163            }
1164
1165            if let Some(line) = meta.line() {
1166                builder_attrs.push(KeyValue::new("code.line.number", line as i64));
1167            }
1168        }
1169
1170        if self.with_threads {
1171            THREAD_ID.with(|id| builder_attrs.push(KeyValue::new("thread.id", *id as i64)));
1172            if let Some(name) = std::thread::current().name() {
1173                // TODO(eliza): it's a bummer that we have to allocate here, but
1174                // we can't easily get the string as a `static`. it would be
1175                // nice if `opentelemetry` could also take `Arc<str>`s as
1176                // `String` values...
1177                builder_attrs.push(KeyValue::new("thread.name", name.to_string()));
1178            }
1179        }
1180
1181        if self.with_level {
1182            builder_attrs.push(KeyValue::new("level", attrs.metadata().level().as_str()));
1183        }
1184        if self.with_target {
1185            builder_attrs.push(KeyValue::new("target", attrs.metadata().target()));
1186        }
1187
1188        let mut updates = SpanBuilderUpdates::default();
1189        attrs.record(&mut SpanAttributeVisitor {
1190            span_builder_updates: &mut updates,
1191            sem_conv_config: self.sem_conv_config,
1192        });
1193
1194        let mut status = Status::Unset;
1195        updates.update(&mut builder, &mut status);
1196        extensions.insert(OtelDataLock::new(OtelData {
1197            state: OtelDataState::Builder {
1198                builder,
1199                parent_cx,
1200                status,
1201            },
1202            end_time: None,
1203        }));
1204    }
1205
1206    fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
1207        if !self.context_activation && !self.tracked_inactivity {
1208            return;
1209        }
1210
1211        let span = ctx.span(id).expect("Span not found, this is a bug");
1212
1213        if self.context_activation {
1214            // We must not hold the extensions when starting the context to avoid potential
1215            // deadlocks.
1216            let otel_data = span.extensions().get::<OtelDataLock>().cloned();
1217            if let Some(otel_data) = otel_data {
1218                self.with_started_cx(&mut otel_data.lock(), &|cx| {
1219                    let guard = prevent_reentrant_call(|| cx.clone().attach());
1220                    GUARD_STACK.with(|stack| stack.borrow_mut().push(id.clone(), guard));
1221                });
1222            }
1223
1224            if !self.tracked_inactivity {
1225                return;
1226            }
1227        }
1228
1229        let mut extensions = span.extensions_mut();
1230
1231        if let Some(timings) = extensions.get_mut::<Timings>() {
1232            if timings.entered_count == 0 {
1233                let now = Instant::now();
1234                timings.idle += (now - timings.last).as_nanos() as i64;
1235                timings.last = now;
1236            }
1237            timings.entered_count += 1;
1238        }
1239    }
1240
1241    fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
1242        let span = ctx.span(id).expect("Span not found, this is a bug");
1243        let mut extensions = span.extensions_mut();
1244
1245        // We don't need mutable access to this but we're taking mutable extensions for timings
1246        // anyway so let's use it instead of locking it twice. This is ok because here we will not
1247        // start the opentelemetry context nor will we call any other code that might use tracing.
1248        if let Some(otel_data) = extensions.get_mut::<OtelDataLock>() {
1249            otel_data.lock().end_time = Some(crate::time::now());
1250            if self.context_activation {
1251                GUARD_STACK.with(|stack| stack.borrow_mut().pop(id));
1252            }
1253        }
1254
1255        if !self.tracked_inactivity {
1256            return;
1257        }
1258
1259        if let Some(timings) = extensions.get_mut::<Timings>() {
1260            timings.entered_count -= 1;
1261            if timings.entered_count == 0 {
1262                let now = Instant::now();
1263                timings.busy += (now - timings.last).as_nanos() as i64;
1264                timings.last = now;
1265            }
1266        }
1267    }
1268
1269    /// Record OpenTelemetry [`attributes`] for the given values.
1270    ///
1271    /// [`attributes`]: opentelemetry::trace::SpanBuilder::attributes
1272    fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
1273        let span = ctx.span(id).expect("Span not found, this is a bug");
1274        let mut updates = SpanBuilderUpdates::default();
1275        values.record(&mut SpanAttributeVisitor {
1276            span_builder_updates: &mut updates,
1277            sem_conv_config: self.sem_conv_config,
1278        });
1279        let extensions = span.extensions();
1280        if let Some(otel_data) = extensions.get::<OtelDataLock>() {
1281            match &mut otel_data.lock().state {
1282                OtelDataState::Builder {
1283                    builder, status, ..
1284                } => {
1285                    // If the builder is present, then update it.
1286                    updates.update(builder, status);
1287                }
1288                OtelDataState::Context { current_cx, .. } => {
1289                    // If the Context has been created, then update the span.
1290                    updates.update_span(&current_cx.span());
1291                }
1292            }
1293        }
1294    }
1295
1296    fn on_follows_from(&self, id: &Id, follows: &Id, ctx: Context<S>) {
1297        let span = ctx.span(id).expect("Span not found, this is a bug");
1298        let otel_data = span.extensions().get::<OtelDataLock>().cloned();
1299        let Some(data) = otel_data else {
1300            return; // The span must already have been closed by us
1301        };
1302
1303        // The follows span may be filtered away (or closed), from this layer,
1304        // in which case we just drop the data, as opposed to panicking. This
1305        // uses the same reasoning as `parent_context` above.
1306        if let Some(follows_span) = ctx.span(follows) {
1307            let follows_extensions = follows_span.extensions();
1308            let follows_otel_data = follows_extensions.get::<OtelDataLock>();
1309            let Some(follows_data) = follows_otel_data else {
1310                return; // The span must already have been closed by us
1311            };
1312
1313            let follows_data = follows_data.clone();
1314            let mut follows_locked = follows_data.lock();
1315            // We drop the extensions lock only after locking the inside. This is because we want to
1316            // hinder potential `close` on the follows span. If we hold one or the other lock, the
1317            // close implementation cannot progress to remove the span.
1318            drop(follows_extensions);
1319
1320            let follows_context =
1321                self.with_started_cx(&mut follows_locked, &|cx| cx.span().span_context().clone());
1322            match &mut data.lock().state {
1323                OtelDataState::Builder { builder, .. } => {
1324                    if let Some(ref mut links) = builder.links {
1325                        links.push(otel::Link::with_context(follows_context));
1326                    } else {
1327                        builder.links = Some(vec![otel::Link::with_context(follows_context)]);
1328                    }
1329                }
1330                OtelDataState::Context { current_cx, .. } => {
1331                    prevent_reentrant_call(|| current_cx.span().add_link(follows_context, vec![]));
1332                }
1333            }
1334        }
1335    }
1336
1337    /// Records OpenTelemetry [`Event`] data on event.
1338    ///
1339    /// Note: an [`ERROR`]-level event will also set the OpenTelemetry span status code to
1340    /// [`Error`], signaling that an error has occurred.
1341    ///
1342    /// [`Event`]: opentelemetry::trace::Event
1343    /// [`ERROR`]: tracing::Level::ERROR
1344    /// [`Error`]: opentelemetry::trace::StatusCode::Error
1345    fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
1346        if INSIDE_TRACING.with(|inside| inside.get()) {
1347            // Ignore reentrant calls.
1348            return;
1349        }
1350        // Ignore events that are not in the context of a span
1351        if let Some(span) = event.parent().and_then(|id| ctx.span(id)).or_else(|| {
1352            event
1353                .is_contextual()
1354                .then(|| ctx.lookup_current())
1355                .flatten()
1356        }) {
1357            // Performing read operations before getting a write lock to avoid a deadlock
1358            // See https://github.com/tokio-rs/tracing/issues/763
1359            #[cfg(feature = "tracing-log")]
1360            let normalized_meta = event.normalized_metadata();
1361            #[cfg(feature = "tracing-log")]
1362            let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
1363            #[cfg(not(feature = "tracing-log"))]
1364            let meta = event.metadata();
1365
1366            let target = Key::new("target");
1367
1368            #[cfg(feature = "tracing-log")]
1369            let target = if normalized_meta.is_some() {
1370                KeyValue::new(target, Value::String(meta.target().to_owned().into()))
1371            } else {
1372                KeyValue::new(target, Value::String(event.metadata().target().into()))
1373            };
1374
1375            #[cfg(not(feature = "tracing-log"))]
1376            let target = KeyValue::new(target, Value::String(meta.target().into()));
1377
1378            let mut otel_event = otel::Event::new(
1379                String::new(),
1380                crate::time::now(),
1381                vec![
1382                    KeyValue::new(
1383                        Key::new("level"),
1384                        Value::String(meta.level().as_str().into()),
1385                    ),
1386                    target,
1387                ],
1388                0,
1389            );
1390
1391            let mut builder_updates = None;
1392            event.record(&mut SpanEventVisitor {
1393                event_builder: &mut otel_event,
1394                span_builder_updates: &mut builder_updates,
1395                sem_conv_config: self.sem_conv_config,
1396            });
1397
1398            // If the event name is still empty, then there was no special handling of error fields.
1399            // It should be safe to set the event name to the name provided by tracing.
1400            // This is a hack but there are existing hacks that depend on the name being empty, so to avoid breaking those the event name is set here.
1401            // Ideally, the name should be set above when the event is constructed.
1402            // see: https://github.com/tokio-rs/tracing-opentelemetry/pull/28
1403            if otel_event.name.is_empty() {
1404                otel_event.name = std::borrow::Cow::Borrowed(event.metadata().name());
1405            }
1406
1407            let otel_data = span.extensions().get::<OtelDataLock>().cloned();
1408
1409            if let Some(otel_data) = otel_data {
1410                if self.location {
1411                    #[cfg(not(feature = "tracing-log"))]
1412                    let normalized_meta: Option<tracing_core::Metadata<'_>> = None;
1413                    let (file, module) = match &normalized_meta {
1414                        Some(meta) => (
1415                            meta.file().map(|s| Value::from(s.to_owned())),
1416                            meta.module_path().map(|s| Value::from(s.to_owned())),
1417                        ),
1418                        None => (
1419                            event.metadata().file().map(Value::from),
1420                            event.metadata().module_path().map(Value::from),
1421                        ),
1422                    };
1423
1424                    if let Some(file) = file {
1425                        otel_event
1426                            .attributes
1427                            .push(KeyValue::new("code.file.path", file));
1428                    }
1429                    if let Some(module) = module {
1430                        otel_event
1431                            .attributes
1432                            .push(KeyValue::new("code.module.name", module));
1433                    }
1434                    if let Some(line) = meta.line() {
1435                        otel_event
1436                            .attributes
1437                            .push(KeyValue::new("code.line.number", line as i64));
1438                    }
1439                }
1440
1441                match &mut otel_data.lock().state {
1442                    OtelDataState::Builder {
1443                        builder, status, ..
1444                    } => {
1445                        if *status == otel::Status::Unset
1446                            && *meta.level() == tracing_core::Level::ERROR
1447                        {
1448                            *status = otel::Status::error("");
1449                        }
1450                        if let Some(builder_updates) = builder_updates {
1451                            builder_updates.update(builder, status);
1452                        }
1453                        if let Some(ref mut events) = builder.events {
1454                            events.push(otel_event);
1455                        } else {
1456                            builder.events = Some(vec![otel_event]);
1457                        }
1458                    }
1459                    OtelDataState::Context { current_cx, .. } => {
1460                        let span = current_cx.span();
1461                        // TODO:ban fix this with accessor in SpanRef that can check the span status
1462                        if *meta.level() == tracing_core::Level::ERROR {
1463                            span.set_status(otel::Status::error(""));
1464                        }
1465                        if let Some(builder_updates) = builder_updates {
1466                            builder_updates.update_span(&span);
1467                        }
1468                        span.add_event(otel_event.name, otel_event.attributes);
1469                    }
1470                }
1471            };
1472        }
1473    }
1474
1475    /// Exports an OpenTelemetry [`Span`] on close.
1476    ///
1477    /// [`Span`]: opentelemetry::trace::Span
1478    fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
1479        let span = ctx.span(&id).expect("Span not found, this is a bug");
1480        // Now get mutable extensions for removal
1481        let (otel_data_lock, timings) = {
1482            let mut extensions = span.extensions_mut();
1483            let timings = if self.tracked_inactivity {
1484                extensions.remove::<Timings>()
1485            } else {
1486                None
1487            };
1488            (extensions.remove::<OtelDataLock>(), timings)
1489        };
1490
1491        if let Some(otel_data_lock) = otel_data_lock {
1492            // If we cannot lock this, someone else is still doing some operations on this span.
1493            // Wait until they're finished.
1494            drop(otel_data_lock.lock());
1495            debug_assert!(
1496                Arc::strong_count(&otel_data_lock.inner) == 1,
1497                "OtelDataLock should not be held by anything else when closing spans. This is a bug in `tracing-opentelemetry`, please file a bug report. This will be ignored when compiled with --release."
1498            );
1499            // We don't use Weak anywhere but this is a sanity check that no one else can ever get a
1500            // hold on the `Arc` again. If we checked just the strong count and someone still had a
1501            // `Weak`, they could upgrade at any time.
1502            debug_assert!(
1503                Arc::weak_count(&otel_data_lock.inner) == 0,
1504                "OtelDataLock should never be made into `Weak`. This is a bug in `tracing-opentelemetry`, please file a bug report. This will be ignored when compiled with --release."
1505            );
1506
1507            let otel_data = Arc::try_unwrap(otel_data_lock.inner)
1508                .map(|lock| lock.into_inner().unwrap())
1509                .unwrap_or_else(|otel_data| otel_data.lock().unwrap().clone());
1510
1511            // Append busy/idle timings when enabled.
1512            let timings = timings.map(|timings| {
1513                let busy_ns = Key::new("busy_ns");
1514                let idle_ns = Key::new("idle_ns");
1515
1516                vec![
1517                    KeyValue::new(busy_ns, timings.busy),
1518                    KeyValue::new(idle_ns, timings.idle),
1519                ]
1520            });
1521
1522            match otel_data.state {
1523                OtelDataState::Builder {
1524                    builder,
1525                    parent_cx,
1526                    status,
1527                } => {
1528                    // We're not holding the extensions lock here so it's fine to just call to
1529                    // opentelemetry and let it log whatever it wants. If we had a lock, we'd have
1530                    // to set the default `Dispatch` to none to prevent deadlocks.
1531                    let mut span = builder.start_with_context(&self.tracer, &parent_cx);
1532                    if let Some(timings) = timings {
1533                        span.set_attributes(timings)
1534                    };
1535                    span.set_status(status.clone());
1536                    if let Some(end_time) = otel_data.end_time {
1537                        span.end_with_timestamp(end_time);
1538                    } else {
1539                        span.end();
1540                    }
1541                }
1542                OtelDataState::Context { current_cx } => {
1543                    let span = current_cx.span();
1544                    if let Some(timings) = timings {
1545                        span.set_attributes(timings)
1546                    };
1547                    otel_data
1548                        .end_time
1549                        .map_or_else(|| span.end(), |end_time| span.end_with_timestamp(end_time));
1550                }
1551            }
1552        }
1553    }
1554
1555    // SAFETY: this is safe because the `WithContext` function pointer is valid
1556    // for the lifetime of `&self`.
1557    unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
1558        match id {
1559            id if id == TypeId::of::<Self>() => Some(self as *const _ as *const ()),
1560            id if id == TypeId::of::<WithContext>() => {
1561                Some(&self.with_context as *const _ as *const ())
1562            }
1563            _ => None,
1564        }
1565    }
1566}
1567
1568struct Timings {
1569    idle: i64,
1570    busy: i64,
1571    last: Instant,
1572    entered_count: u64,
1573}
1574
1575impl Timings {
1576    fn new() -> Self {
1577        Self {
1578            idle: 0,
1579            busy: 0,
1580            last: Instant::now(),
1581            entered_count: 0,
1582        }
1583    }
1584}
1585
1586fn thread_id_integer(id: thread::ThreadId) -> u64 {
1587    let thread_id = format!("{id:?}");
1588    thread_id
1589        .trim_start_matches("ThreadId(")
1590        .trim_end_matches(')')
1591        .parse::<u64>()
1592        .expect("thread ID should parse as an integer")
1593}
1594
1595#[cfg(test)]
1596mod tests {
1597    use crate::OpenTelemetrySpanExt;
1598
1599    use super::*;
1600    use opentelemetry::trace::{SpanContext, TraceFlags, TracerProvider};
1601    use opentelemetry_sdk::trace::SpanExporter;
1602    use std::{collections::HashMap, error::Error, fmt::Display, time::SystemTime};
1603    use tracing::trace_span;
1604    use tracing_core::LevelFilter;
1605    use tracing_subscriber::prelude::*;
1606
1607    #[derive(Debug, Clone)]
1608    struct TestTracer {
1609        tracer: opentelemetry_sdk::trace::Tracer,
1610        exporter: opentelemetry_sdk::trace::InMemorySpanExporter,
1611    }
1612
1613    impl TestTracer {
1614        fn spans(&mut self) -> Vec<opentelemetry_sdk::trace::SpanData> {
1615            self.exporter
1616                .force_flush()
1617                .expect("problems flushing spans");
1618            self.exporter
1619                .get_finished_spans()
1620                .expect("problems recording spans")
1621        }
1622
1623        fn with_data<T>(&mut self, f: impl FnOnce(&opentelemetry_sdk::trace::SpanData) -> T) -> T {
1624            let spans = self.spans();
1625            f(spans.first().expect("no spans recorded"))
1626        }
1627
1628        fn attributes(&mut self) -> HashMap<String, Value> {
1629            self.with_data(|data| {
1630                data.attributes
1631                    .iter()
1632                    .map(|kv| (kv.key.to_string(), kv.value.clone()))
1633                    .collect()
1634            })
1635        }
1636    }
1637
1638    impl Default for TestTracer {
1639        fn default() -> Self {
1640            let exporter = opentelemetry_sdk::trace::InMemorySpanExporter::default();
1641            let provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
1642                .with_simple_exporter(exporter.clone())
1643                .build();
1644            let tracer = provider.tracer("test-tracer");
1645            Self { tracer, exporter }
1646        }
1647    }
1648
1649    impl opentelemetry::trace::Tracer for TestTracer {
1650        type Span = opentelemetry_sdk::trace::Span;
1651
1652        fn build_with_context(&self, builder: SpanBuilder, parent_cx: &OtelContext) -> Self::Span {
1653            self.tracer.build_with_context(builder, parent_cx)
1654        }
1655    }
1656
1657    #[derive(Debug, Clone)]
1658    struct TestSpan(otel::SpanContext);
1659    impl otel::Span for TestSpan {
1660        fn add_event_with_timestamp<T: Into<Cow<'static, str>>>(
1661            &mut self,
1662            _: T,
1663            _: SystemTime,
1664            _: Vec<KeyValue>,
1665        ) {
1666        }
1667        fn span_context(&self) -> &otel::SpanContext {
1668            &self.0
1669        }
1670        fn is_recording(&self) -> bool {
1671            false
1672        }
1673        fn set_attribute(&mut self, _attribute: KeyValue) {}
1674        fn set_status(&mut self, _status: otel::Status) {}
1675        fn update_name<T: Into<Cow<'static, str>>>(&mut self, _new_name: T) {}
1676        fn add_link(&mut self, _span_context: SpanContext, _attributes: Vec<KeyValue>) {}
1677        fn end_with_timestamp(&mut self, _timestamp: SystemTime) {}
1678    }
1679
1680    #[derive(Debug)]
1681    struct TestDynError {
1682        msg: &'static str,
1683        source: Option<Box<TestDynError>>,
1684    }
1685    impl Display for TestDynError {
1686        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1687            write!(f, "{}", self.msg)
1688        }
1689    }
1690    impl Error for TestDynError {
1691        fn source(&self) -> Option<&(dyn Error + 'static)> {
1692            match &self.source {
1693                Some(source) => Some(source),
1694                None => None,
1695            }
1696        }
1697    }
1698    impl TestDynError {
1699        fn new(msg: &'static str) -> Self {
1700            Self { msg, source: None }
1701        }
1702        fn with_parent(self, parent_msg: &'static str) -> Self {
1703            Self {
1704                msg: parent_msg,
1705                source: Some(Box::new(self)),
1706            }
1707        }
1708    }
1709
1710    #[test]
1711    fn dynamic_span_names() {
1712        let dynamic_name = "GET http://example.com".to_string();
1713        let mut tracer = TestTracer::default();
1714        let subscriber = tracing_subscriber::registry().with(layer().with_tracer(tracer.clone()));
1715
1716        tracing::subscriber::with_default(subscriber, || {
1717            tracing::debug_span!("static_name", otel.name = dynamic_name.as_str());
1718        });
1719
1720        let recorded_name = tracer.spans().first().unwrap().name.clone();
1721        assert_eq!(recorded_name, dynamic_name.as_str())
1722    }
1723
1724    #[test]
1725    fn span_kind() {
1726        let mut tracer = TestTracer::default();
1727        let subscriber = tracing_subscriber::registry().with(layer().with_tracer(tracer.clone()));
1728
1729        tracing::subscriber::with_default(subscriber, || {
1730            tracing::debug_span!("request", otel.kind = "server");
1731        });
1732
1733        let recorded_kind = tracer.with_data(|data| data.span_kind.clone());
1734        assert_eq!(recorded_kind, otel::SpanKind::Server)
1735    }
1736
1737    #[test]
1738    fn span_status_code() {
1739        let mut tracer = TestTracer::default();
1740        let subscriber = tracing_subscriber::registry().with(layer().with_tracer(tracer.clone()));
1741
1742        tracing::subscriber::with_default(subscriber, || {
1743            tracing::debug_span!("request", otel.status_code = ?otel::Status::Ok);
1744        });
1745
1746        let recorded_status = tracer.with_data(|data| data.status.clone());
1747        assert_eq!(recorded_status, otel::Status::Ok)
1748    }
1749
1750    #[test]
1751    fn span_status_description() {
1752        let mut tracer = TestTracer::default();
1753        let subscriber = tracing_subscriber::registry().with(layer().with_tracer(tracer.clone()));
1754
1755        let message = "message";
1756
1757        tracing::subscriber::with_default(subscriber, || {
1758            tracing::debug_span!("request", otel.status_description = message);
1759        });
1760
1761        let recorded_status_message = tracer.with_data(|data| data.status.clone());
1762
1763        assert_eq!(recorded_status_message, otel::Status::error(message))
1764    }
1765
1766    #[test]
1767    fn trace_id_from_existing_context_with_context_activation() {
1768        trace_id_from_existing_context_impl(true);
1769    }
1770
1771    #[test]
1772    fn trace_id_from_existing_context_no_context_activation() {
1773        trace_id_from_existing_context_impl(false);
1774    }
1775
1776    fn trace_id_from_existing_context_impl(context_activation: bool) {
1777        let mut tracer = TestTracer::default();
1778        let subscriber = tracing_subscriber::registry().with(
1779            layer()
1780                .with_tracer(tracer.clone())
1781                .with_context_activation(context_activation),
1782        );
1783        let trace_id = otel::TraceId::from(42u128);
1784        let existing_cx = OtelContext::current_with_span(TestSpan(otel::SpanContext::new(
1785            trace_id,
1786            otel::SpanId::from(1u64),
1787            TraceFlags::SAMPLED,
1788            false,
1789            Default::default(),
1790        )));
1791        let _g = existing_cx.attach();
1792
1793        tracing::subscriber::with_default(subscriber, || {
1794            tracing::debug_span!("request", otel.kind = "server");
1795        });
1796
1797        let recorded_trace_id = tracer.with_data(|data| data.span_context.trace_id());
1798        assert_eq!(recorded_trace_id, trace_id)
1799    }
1800
1801    #[test]
1802    fn includes_timings_with_context_activation() {
1803        includes_timings_impl(true);
1804    }
1805
1806    #[test]
1807    fn includes_timings_no_context_activation() {
1808        includes_timings_impl(false);
1809    }
1810
1811    fn includes_timings_impl(context_activation: bool) {
1812        let mut tracer = TestTracer::default();
1813        let subscriber = tracing_subscriber::registry().with(
1814            layer()
1815                .with_tracer(tracer.clone())
1816                .with_tracked_inactivity(true)
1817                .with_context_activation(context_activation),
1818        );
1819
1820        tracing::subscriber::with_default(subscriber, || {
1821            tracing::debug_span!("request");
1822        });
1823
1824        let attributes = tracer.attributes();
1825
1826        assert!(attributes.contains_key("idle_ns"));
1827        assert!(attributes.contains_key("busy_ns"));
1828    }
1829
1830    #[test]
1831    fn records_error_fields_with_context_activation() {
1832        records_error_fields_impl(true);
1833    }
1834
1835    #[test]
1836    fn records_error_fields_no_context_activation() {
1837        records_error_fields_impl(false);
1838    }
1839
1840    fn records_error_fields_impl(context_activation: bool) {
1841        let mut tracer = TestTracer::default();
1842        let subscriber = tracing_subscriber::registry().with(
1843            layer()
1844                .with_tracer(tracer.clone())
1845                .with_context_activation(context_activation),
1846        );
1847
1848        let err = TestDynError::new("base error")
1849            .with_parent("intermediate error")
1850            .with_parent("user error");
1851
1852        tracing::subscriber::with_default(subscriber, || {
1853            tracing::debug_span!(
1854                "request",
1855                error = &err as &(dyn std::error::Error + 'static)
1856            );
1857        });
1858
1859        let attributes = tracer.attributes();
1860
1861        assert_eq!(attributes["error"].as_str(), "user error");
1862        assert_eq!(
1863            attributes["error.chain"],
1864            Value::Array(
1865                vec![
1866                    StringValue::from("intermediate error"),
1867                    StringValue::from("base error")
1868                ]
1869                .into()
1870            )
1871        );
1872
1873        assert_eq!(attributes[FIELD_EXCEPTION_MESSAGE].as_str(), "user error");
1874        assert_eq!(
1875            attributes[FIELD_EXCEPTION_STACKTRACE],
1876            Value::Array(
1877                vec![
1878                    StringValue::from("intermediate error"),
1879                    StringValue::from("base error")
1880                ]
1881                .into()
1882            )
1883        );
1884    }
1885
1886    #[test]
1887    fn records_event_name_with_context_activation() {
1888        records_event_name_impl(true);
1889    }
1890
1891    #[test]
1892    fn records_event_name_no_context_activation() {
1893        records_event_name_impl(false);
1894    }
1895
1896    fn records_event_name_impl(context_activation: bool) {
1897        let mut tracer = TestTracer::default();
1898        let subscriber = tracing_subscriber::registry().with(
1899            layer()
1900                .with_tracer(tracer.clone())
1901                .with_context_activation(context_activation),
1902        );
1903
1904        tracing::subscriber::with_default(subscriber, || {
1905            tracing::debug_span!("test span").in_scope(|| {
1906                tracing::event!(tracing::Level::INFO, "event name 1"); // this is equivalent to 'message = "event name 1"'
1907                tracing::event!(name: "event name 2", tracing::Level::INFO, field1 = "field1");
1908                tracing::event!(name: "event name 3", tracing::Level::INFO, error = "field2");
1909                tracing::event!(name: "event name 4", tracing::Level::INFO, message = "field3");
1910                tracing::event!(name: "event name 5", tracing::Level::INFO, name = "field4");
1911            });
1912        });
1913
1914        let events = tracer.with_data(|data| data.events.clone());
1915
1916        let mut iter = events.iter();
1917
1918        assert_eq!(iter.next().unwrap().name, "event name 1");
1919        assert_eq!(iter.next().unwrap().name, "event name 2");
1920        assert_eq!(iter.next().unwrap().name, "exception"); // error attribute is handled specially
1921        assert_eq!(iter.next().unwrap().name, "field3"); // message attribute is handled specially
1922        assert_eq!(iter.next().unwrap().name, "event name 5"); // name attribute should not conflict with event name.
1923    }
1924
1925    #[test]
1926    #[cfg(not(__reentrant_tracing_test))] // The counts would be wrong
1927    fn event_filter_count() {
1928        let mut tracer = TestTracer::default();
1929        let subscriber = tracing_subscriber::registry().with(
1930            layer()
1931                .with_tracer(tracer.clone())
1932                .with_counting_event_filter(LevelFilter::INFO)
1933                .with_filter(LevelFilter::DEBUG),
1934        );
1935
1936        tracing::subscriber::with_default(subscriber, || {
1937            tracing::debug_span!("test span").in_scope(|| {
1938                tracing::event!(tracing::Level::TRACE, "1");
1939                tracing::event!(tracing::Level::DEBUG, "2");
1940                tracing::event!(tracing::Level::INFO, "3");
1941                tracing::event!(tracing::Level::WARN, "4");
1942                tracing::event!(tracing::Level::ERROR, "5");
1943            });
1944        });
1945
1946        let events = tracer.with_data(|data| data.events.clone());
1947
1948        let mut iter = events.iter();
1949
1950        assert_eq!(iter.next().unwrap().name, "3");
1951        assert_eq!(iter.next().unwrap().name, "4");
1952        assert_eq!(iter.next().unwrap().name, "5");
1953        assert!(iter.next().is_none());
1954
1955        let spans = tracer.spans();
1956        assert_eq!(spans.len(), 1);
1957
1958        let Value::I64(event_count) = spans
1959            .first()
1960            .unwrap()
1961            .attributes
1962            .iter()
1963            .find(|key_value| key_value.key.as_str() == SPAN_EVENT_COUNT_FIELD)
1964            .unwrap()
1965            .value
1966        else {
1967            panic!("Unexpected type of `{SPAN_EVENT_COUNT_FIELD}`.");
1968        };
1969        // We've sent 5 events out of which 1 was filtered out by an actual filter and another by
1970        // our event filter.
1971        assert_eq!(event_count, 4);
1972    }
1973
1974    #[test]
1975    fn records_no_error_fields_with_context_activation() {
1976        records_no_error_fields_impl(true);
1977    }
1978
1979    #[test]
1980    fn records_no_error_fields_no_context_activation() {
1981        records_no_error_fields_impl(false);
1982    }
1983
1984    fn records_no_error_fields_impl(context_activation: bool) {
1985        let mut tracer = TestTracer::default();
1986        let subscriber = tracing_subscriber::registry().with(
1987            layer()
1988                .with_error_records_to_exceptions(false)
1989                .with_tracer(tracer.clone())
1990                .with_context_activation(context_activation),
1991        );
1992
1993        let err = TestDynError::new("base error")
1994            .with_parent("intermediate error")
1995            .with_parent("user error");
1996
1997        tracing::subscriber::with_default(subscriber, || {
1998            tracing::debug_span!(
1999                "request",
2000                error = &err as &(dyn std::error::Error + 'static)
2001            );
2002        });
2003
2004        let attributes = tracer.attributes();
2005
2006        assert_eq!(attributes["error"].as_str(), "user error");
2007        assert_eq!(
2008            attributes["error.chain"],
2009            Value::Array(
2010                vec![
2011                    StringValue::from("intermediate error"),
2012                    StringValue::from("base error")
2013                ]
2014                .into()
2015            )
2016        );
2017
2018        assert_eq!(attributes[FIELD_EXCEPTION_MESSAGE].as_str(), "user error");
2019        assert_eq!(
2020            attributes[FIELD_EXCEPTION_STACKTRACE],
2021            Value::Array(
2022                vec![
2023                    StringValue::from("intermediate error"),
2024                    StringValue::from("base error")
2025                ]
2026                .into()
2027            )
2028        );
2029    }
2030
2031    #[test]
2032    fn includes_span_location_with_context_activation() {
2033        includes_span_location_impl(true);
2034    }
2035
2036    #[test]
2037    fn includes_span_location_no_context_activation() {
2038        includes_span_location_impl(false);
2039    }
2040
2041    fn includes_span_location_impl(context_activation: bool) {
2042        let mut tracer = TestTracer::default();
2043        let subscriber = tracing_subscriber::registry().with(
2044            layer()
2045                .with_tracer(tracer.clone())
2046                .with_location(true)
2047                .with_context_activation(context_activation),
2048        );
2049
2050        tracing::subscriber::with_default(subscriber, || {
2051            tracing::debug_span!("request");
2052        });
2053
2054        let attributes = tracer.attributes();
2055
2056        assert!(attributes.contains_key("code.file.path"));
2057        assert!(attributes.contains_key("code.module.name"));
2058        assert!(attributes.contains_key("code.line.number"));
2059    }
2060
2061    #[test]
2062    fn excludes_span_location_with_context_activation() {
2063        excludes_span_location_impl(true);
2064    }
2065
2066    #[test]
2067    fn excludes_span_location_no_context_activation() {
2068        excludes_span_location_impl(false);
2069    }
2070
2071    fn excludes_span_location_impl(context_activation: bool) {
2072        let mut tracer = TestTracer::default();
2073        let subscriber = tracing_subscriber::registry().with(
2074            layer()
2075                .with_tracer(tracer.clone())
2076                .with_location(false)
2077                .with_context_activation(context_activation),
2078        );
2079
2080        tracing::subscriber::with_default(subscriber, || {
2081            tracing::debug_span!("request");
2082        });
2083
2084        let attributes = tracer.attributes();
2085
2086        assert!(!attributes.contains_key("code.file.path"));
2087        assert!(!attributes.contains_key("code.module.name"));
2088        assert!(!attributes.contains_key("code.line.number"));
2089    }
2090
2091    #[test]
2092    fn includes_thread_with_context_activation() {
2093        includes_thread_impl(true);
2094    }
2095
2096    #[test]
2097    fn includes_thread_no_context_activation() {
2098        includes_thread_impl(false);
2099    }
2100
2101    fn includes_thread_impl(context_activation: bool) {
2102        let thread = thread::current();
2103        let expected_name = thread
2104            .name()
2105            .map(|name| Value::String(name.to_owned().into()));
2106        let expected_id = Value::I64(thread_id_integer(thread.id()) as i64);
2107
2108        let mut tracer = TestTracer::default();
2109        let subscriber = tracing_subscriber::registry().with(
2110            layer()
2111                .with_tracer(tracer.clone())
2112                .with_threads(true)
2113                .with_context_activation(context_activation),
2114        );
2115
2116        tracing::subscriber::with_default(subscriber, || {
2117            tracing::debug_span!("request");
2118        });
2119
2120        let attributes = tracer.attributes();
2121
2122        assert_eq!(attributes.get("thread.name"), expected_name.as_ref());
2123        assert_eq!(attributes.get("thread.id"), Some(&expected_id));
2124    }
2125
2126    #[test]
2127    fn excludes_thread_with_context_activation() {
2128        excludes_thread_impl(true);
2129    }
2130
2131    #[test]
2132    fn excludes_thread_no_context_activation() {
2133        excludes_thread_impl(false);
2134    }
2135
2136    fn excludes_thread_impl(context_activation: bool) {
2137        let mut tracer = TestTracer::default();
2138        let subscriber = tracing_subscriber::registry().with(
2139            layer()
2140                .with_tracer(tracer.clone())
2141                .with_threads(false)
2142                .with_context_activation(context_activation),
2143        );
2144
2145        tracing::subscriber::with_default(subscriber, || {
2146            tracing::debug_span!("request");
2147        });
2148
2149        let attributes = tracer.attributes();
2150
2151        assert!(!attributes.contains_key("thread.name"));
2152        assert!(!attributes.contains_key("thread.id"));
2153    }
2154
2155    #[test]
2156    fn includes_level_with_context_activation() {
2157        includes_level_impl(true);
2158    }
2159
2160    #[test]
2161    fn includes_level_no_context_activation() {
2162        includes_level_impl(false);
2163    }
2164
2165    fn includes_level_impl(context_activation: bool) {
2166        let mut tracer = TestTracer::default();
2167        let subscriber = tracing_subscriber::registry().with(
2168            layer()
2169                .with_tracer(tracer.clone())
2170                .with_level(true)
2171                .with_context_activation(context_activation),
2172        );
2173
2174        tracing::subscriber::with_default(subscriber, || {
2175            tracing::debug_span!("request");
2176        });
2177
2178        let attributes = tracer.attributes();
2179
2180        assert!(attributes.contains_key("level"));
2181    }
2182
2183    #[test]
2184    fn excludes_level_with_context_activation() {
2185        excludes_level_impl(true);
2186    }
2187
2188    #[test]
2189    fn excludes_level_no_context_activation() {
2190        excludes_level_impl(false);
2191    }
2192
2193    fn excludes_level_impl(context_activation: bool) {
2194        let mut tracer = TestTracer::default();
2195        let subscriber = tracing_subscriber::registry().with(
2196            layer()
2197                .with_tracer(tracer.clone())
2198                .with_level(false)
2199                .with_context_activation(context_activation),
2200        );
2201
2202        tracing::subscriber::with_default(subscriber, || {
2203            tracing::debug_span!("request");
2204        });
2205
2206        let attributes = tracer.attributes();
2207
2208        assert!(!attributes.contains_key("level"));
2209    }
2210
2211    #[test]
2212    fn includes_target() {
2213        let mut tracer = TestTracer::default();
2214        let subscriber = tracing_subscriber::registry()
2215            .with(layer().with_tracer(tracer.clone()).with_target(true));
2216
2217        tracing::subscriber::with_default(subscriber, || {
2218            tracing::debug_span!("request");
2219        });
2220
2221        let attributes = tracer.attributes();
2222        let keys = attributes.keys().map(|k| k.as_str()).collect::<Vec<&str>>();
2223        assert!(keys.contains(&"target"));
2224    }
2225
2226    #[test]
2227    fn excludes_target() {
2228        let mut tracer = TestTracer::default();
2229        let subscriber = tracing_subscriber::registry()
2230            .with(layer().with_tracer(tracer.clone()).with_target(false));
2231
2232        tracing::subscriber::with_default(subscriber, || {
2233            tracing::debug_span!("request");
2234        });
2235
2236        let attributes = tracer.attributes();
2237        let keys = attributes.keys().map(|k| k.as_str()).collect::<Vec<&str>>();
2238        assert!(!keys.contains(&"target"));
2239    }
2240
2241    #[test]
2242    fn propagates_error_fields_from_event_to_span_with_context_activation() {
2243        propagates_error_fields_from_event_to_span_impl(true);
2244    }
2245
2246    #[test]
2247    fn propagates_error_fields_from_event_to_span_no_context_activation() {
2248        propagates_error_fields_from_event_to_span_impl(false);
2249    }
2250
2251    fn propagates_error_fields_from_event_to_span_impl(context_activation: bool) {
2252        let mut tracer = TestTracer::default();
2253        let subscriber = tracing_subscriber::registry().with(
2254            layer()
2255                .with_tracer(tracer.clone())
2256                .with_context_activation(context_activation),
2257        );
2258
2259        let err = TestDynError::new("base error")
2260            .with_parent("intermediate error")
2261            .with_parent("user error");
2262
2263        tracing::subscriber::with_default(subscriber, || {
2264            let _guard = tracing::debug_span!("request",).entered();
2265
2266            tracing::error!(
2267                error = &err as &(dyn std::error::Error + 'static),
2268                "request error!"
2269            )
2270        });
2271
2272        let attributes = tracer.attributes();
2273
2274        assert_eq!(attributes[FIELD_EXCEPTION_MESSAGE].as_str(), "user error");
2275        assert_eq!(
2276            attributes[FIELD_EXCEPTION_STACKTRACE],
2277            Value::Array(
2278                vec![
2279                    StringValue::from("intermediate error"),
2280                    StringValue::from("base error")
2281                ]
2282                .into()
2283            )
2284        );
2285    }
2286
2287    #[test]
2288    fn propagates_no_error_fields_from_event_to_span_with_context_activation() {
2289        propagates_no_error_fields_from_event_to_span_impl(true);
2290    }
2291
2292    #[test]
2293    fn propagates_no_error_fields_from_event_to_span_no_context_activation() {
2294        propagates_no_error_fields_from_event_to_span_impl(false);
2295    }
2296
2297    fn propagates_no_error_fields_from_event_to_span_impl(context_activation: bool) {
2298        let mut tracer = TestTracer::default();
2299        let subscriber = tracing_subscriber::registry().with(
2300            layer()
2301                .with_error_fields_to_exceptions(false)
2302                .with_tracer(tracer.clone())
2303                .with_context_activation(context_activation),
2304        );
2305
2306        let err = TestDynError::new("base error")
2307            .with_parent("intermediate error")
2308            .with_parent("user error");
2309
2310        tracing::subscriber::with_default(subscriber, || {
2311            let _guard = tracing::debug_span!("request",).entered();
2312
2313            tracing::error!(
2314                error = &err as &(dyn std::error::Error + 'static),
2315                "request error!"
2316            )
2317        });
2318
2319        let attributes = tracer.attributes();
2320
2321        assert_eq!(attributes[FIELD_EXCEPTION_MESSAGE].as_str(), "user error");
2322        assert_eq!(
2323            attributes[FIELD_EXCEPTION_STACKTRACE],
2324            Value::Array(
2325                vec![
2326                    StringValue::from("intermediate error"),
2327                    StringValue::from("base error")
2328                ]
2329                .into()
2330            )
2331        );
2332    }
2333
2334    #[test]
2335    fn tracing_error_compatibility_with_context_activation() {
2336        tracing_error_compatibility_impl(true);
2337    }
2338
2339    #[test]
2340    fn tracing_error_compatibility_no_context_activation() {
2341        tracing_error_compatibility_impl(false);
2342    }
2343
2344    fn tracing_error_compatibility_impl(context_activation: bool) {
2345        let tracer = TestTracer::default();
2346        let subscriber = tracing_subscriber::registry()
2347            .with(
2348                layer()
2349                    .with_error_fields_to_exceptions(false)
2350                    .with_tracer(tracer.clone())
2351                    .with_context_activation(context_activation),
2352            )
2353            .with(tracing_error::ErrorLayer::default());
2354
2355        tracing::subscriber::with_default(subscriber, || {
2356            let span = tracing::info_span!("Blows up!", exception = tracing::field::Empty);
2357            let _entered = span.enter();
2358            let context = tracing_error::SpanTrace::capture();
2359
2360            // This can cause a deadlock if `on_record` locks extensions while attributes are visited
2361            span.record("exception", tracing::field::debug(&context));
2362            // This can cause a deadlock if `on_event` locks extensions while the event is visited
2363            tracing::info!(exception = &tracing::field::debug(&context), "hello");
2364        });
2365
2366        // No need to assert anything, as long as this finished (and did not panic), everything is ok.
2367    }
2368
2369    #[derive(Debug, PartialEq)]
2370    struct ValueA(&'static str);
2371    #[derive(Debug, PartialEq)]
2372    struct ValueB(&'static str);
2373
2374    #[test]
2375    fn otel_context_propagation() {
2376        use opentelemetry::trace::Tracer;
2377        use tracing::span;
2378
2379        let mut tracer = TestTracer::default();
2380        let subscriber = tracing_subscriber::registry().with(layer().with_tracer(tracer.clone()));
2381
2382        tracing::subscriber::with_default(subscriber, || {
2383            // Add a value to the current OpenTelemetry context for the bridge to propagate
2384            let _outer_guard =
2385                OtelContext::attach(OtelContext::default().with_value(ValueA("outer")));
2386            assert_eq!(OtelContext::current().get(), Some(&ValueA("outer")));
2387            let root = span!(tracing::Level::TRACE, "tokio-tracing-span-parent");
2388            // Drop the guard to ensure the context is cleared
2389            drop(_outer_guard);
2390            assert!(OtelContext::current().get::<ValueA>().is_none());
2391            // Enter the root span, the context should be propagated
2392            let _enter_root = root.enter();
2393            assert_eq!(OtelContext::current().get(), Some(&ValueA("outer")));
2394            // Add another value to the current OpenTelemetry context for the bridge to propagate
2395            let _inner_guard =
2396                OtelContext::attach(OtelContext::current_with_value(ValueB("inner")));
2397            assert_eq!(OtelContext::current().get(), Some(&ValueA("outer")));
2398            assert_eq!(OtelContext::current().get(), Some(&ValueB("inner")));
2399            let child = span!(tracing::Level::TRACE, "tokio-tracing-span-child");
2400            // Drop the guard to ensure the context is reverted
2401            drop(_inner_guard);
2402            assert_eq!(OtelContext::current().get(), Some(&ValueA("outer")));
2403            assert!(OtelContext::current().get::<ValueB>().is_none());
2404            // Enter the child span, the context should be propagated
2405            let _enter_child = child.enter();
2406            assert_eq!(OtelContext::current().get(), Some(&ValueA("outer")));
2407            assert_eq!(OtelContext::current().get(), Some(&ValueB("inner")));
2408            // Create an OpenTelemetry span using the OpenTelemetry notion of current
2409            // span to see check that it is a child of the tokio child span
2410            let span = tracer
2411                .tracer
2412                .span_builder("otel-tracing-span")
2413                .start(&tracer);
2414            let _otel_guard = OtelContext::attach(OtelContext::current_with_span(span));
2415            let child2 = span!(tracing::Level::TRACE, "tokio-tracing-span-child2");
2416            drop(_otel_guard);
2417            // Drop the child span, the context should be reverted
2418            drop(_enter_child);
2419            assert_eq!(OtelContext::current().get(), Some(&ValueA("outer")));
2420            assert!(OtelContext::current().get::<ValueB>().is_none());
2421            // Drop the root span, the context should be reverted
2422            drop(_enter_root);
2423            assert!(OtelContext::current().get::<ValueA>().is_none());
2424            assert!(OtelContext::current().get::<ValueB>().is_none());
2425            let _ = child2.enter();
2426        });
2427
2428        // Let's check the spans
2429        let spans = tracer.spans();
2430        let parent = spans
2431            .iter()
2432            .find(|span| span.name == "tokio-tracing-span-parent")
2433            .unwrap();
2434        let child = spans
2435            .iter()
2436            .find(|span| span.name == "tokio-tracing-span-child")
2437            .unwrap();
2438        let child2 = spans
2439            .iter()
2440            .find(|span| span.name == "tokio-tracing-span-child2")
2441            .unwrap();
2442        let otel = spans
2443            .iter()
2444            .find(|span| span.name == "otel-tracing-span")
2445            .unwrap();
2446        // The tokio parent span should be a root span
2447        assert_eq!(parent.parent_span_id, otel::SpanId::INVALID);
2448        // The first tokio child span should have the tokio parent span as parent
2449        assert_eq!(child.parent_span_id, parent.span_context.span_id());
2450        // The otel span should have the first tokio child span as parent
2451        assert_eq!(otel.parent_span_id, child.span_context.span_id());
2452        // The second tokio child span should have the otel span as parent
2453        assert_eq!(child2.parent_span_id, otel.span_context.span_id());
2454    }
2455
2456    #[test]
2457    fn parent_context() {
2458        let mut tracer = TestTracer::default();
2459        let subscriber = tracing_subscriber::registry().with(layer().with_tracer(tracer.clone()));
2460
2461        tracing::subscriber::with_default(subscriber, || {
2462            let root = trace_span!("root");
2463
2464            let child1 = trace_span!("child-1");
2465            let root_context = root.context(); // SpanData (None)
2466            let _ = child1.set_parent(root_context); // Clone context, but SpanData(None)
2467
2468            let _enter_root = root.enter();
2469            drop(_enter_root);
2470
2471            let child2 = trace_span!("child-2");
2472            let _ = child2.set_parent(root.context());
2473        });
2474
2475        // Let's check the spans
2476        let spans = tracer.spans();
2477        let parent = spans.iter().find(|span| span.name == "root").unwrap();
2478        let child1 = spans.iter().find(|span| span.name == "child-1").unwrap();
2479        let child2 = spans.iter().find(|span| span.name == "child-2").unwrap();
2480        assert_eq!(parent.parent_span_id, otel::SpanId::INVALID);
2481        assert_eq!(child1.parent_span_id, parent.span_context.span_id());
2482        assert_eq!(child2.parent_span_id, parent.span_context.span_id());
2483    }
2484
2485    #[test]
2486    fn record_after_with_context_activation() {
2487        record_after_impl(true);
2488    }
2489
2490    #[test]
2491    fn record_after_no_context_activation() {
2492        record_after_impl(false);
2493    }
2494
2495    fn record_after_impl(context_activation: bool) {
2496        let mut tracer = TestTracer::default();
2497        let subscriber = tracing_subscriber::registry().with(
2498            layer()
2499                .with_tracer(tracer.clone())
2500                .with_context_activation(context_activation),
2501        );
2502
2503        tracing::subscriber::with_default(subscriber, || {
2504            let root = trace_span!("root", before = "before", after = "before");
2505
2506            // Record a value before the span is entered
2507            root.record("before", "after");
2508
2509            // Enter and exit the span
2510            let _enter_root = root.enter();
2511            drop(_enter_root);
2512
2513            // Record a value after the span is exited
2514            root.record("after", "after");
2515        });
2516
2517        // Let's check the spans. Both values should've been
2518        // updated to 'after'.
2519        let spans = tracer.spans();
2520        let parent = spans.iter().find(|span| span.name == "root").unwrap();
2521        assert_eq!(parent.parent_span_id, otel::SpanId::INVALID);
2522        assert!(parent
2523            .attributes
2524            .iter()
2525            .filter(|kv| kv.key.as_str() == "before")
2526            .any(|kv| kv.value.as_str() == "after"));
2527
2528        assert!(parent
2529            .attributes
2530            .iter()
2531            .filter(|kv| kv.key.as_str() == "after")
2532            .any(|kv| kv.value.as_str() == "after"));
2533    }
2534
2535    #[test]
2536    fn parent_context_2() {
2537        let mut tracer = TestTracer::default();
2538        let subscriber = tracing_subscriber::registry().with(layer().with_tracer(tracer.clone()));
2539
2540        tracing::subscriber::with_default(subscriber, || {
2541            let root = trace_span!("root");
2542            _ = root.enter();
2543
2544            let child1 = trace_span!("child-1");
2545            let _ = child1.set_parent(root.context());
2546
2547            trace_span!(parent: &child1, "child-2");
2548            let _ = child1.set_parent(root.context()); // <-- this is what causes the issue
2549
2550            trace_span!(parent: &child1, "child-3");
2551        });
2552
2553        // Let's check the spans
2554        let spans = tracer.spans();
2555        let root = spans.iter().find(|span| span.name == "root").unwrap();
2556        let child1 = spans.iter().find(|span| span.name == "child-1").unwrap();
2557        let child2 = spans.iter().find(|span| span.name == "child-2").unwrap();
2558        let child3 = spans.iter().find(|span| span.name == "child-3").unwrap();
2559        assert_eq!(root.parent_span_id, otel::SpanId::INVALID);
2560        assert_eq!(child1.parent_span_id, root.span_context.span_id());
2561        assert_eq!(child2.parent_span_id, child1.span_context.span_id());
2562
2563        // The parent should be `child1`
2564        assert_eq!(child3.parent_span_id, child1.span_context.span_id());
2565    }
2566
2567    #[test]
2568    fn follows_from_adds_link_with_context_activation() {
2569        follows_from_adds_link_impl(true);
2570    }
2571
2572    #[test]
2573    fn follows_from_adds_link_no_context_activation() {
2574        follows_from_adds_link_impl(false);
2575    }
2576
2577    fn follows_from_adds_link_impl(context_activation: bool) {
2578        use crate::OpenTelemetrySpanExt;
2579        let mut tracer = TestTracer::default();
2580        let subscriber = tracing_subscriber::registry().with(
2581            layer()
2582                .with_tracer(tracer.clone())
2583                .with_context_activation(context_activation),
2584        );
2585
2586        let span1_id = tracing::subscriber::with_default(subscriber, || {
2587            let span2 = tracing::debug_span!("span2");
2588            let span1 = tracing::debug_span!("span1");
2589
2590            // Ensure that span2 is started
2591            let _ = span2.context();
2592
2593            // Establish follows_from relationship
2594            span2.follows_from(&span1);
2595
2596            // Enter span2 to ensure it's exported
2597            let _guard = span2.enter();
2598
2599            // Get span ID for later verification
2600            span1.context().span().span_context().span_id()
2601        });
2602
2603        let spans = tracer.spans();
2604        // Check that both spans are exported
2605        assert_eq!(spans.len(), 2, "Expected two spans to be exported");
2606        assert!(spans.iter().any(|span| span.name == "span1"));
2607        let span2 = spans
2608            .iter()
2609            .find(|span| span.name == "span2")
2610            .expect("Expected span2 to be exported");
2611
2612        // Collect span2 links
2613        let links = span2
2614            .links
2615            .iter()
2616            .map(|link| link.span_context.span_id())
2617            .collect::<Vec<_>>();
2618
2619        // Verify that span2 has a link to span1
2620        assert_eq!(
2621            links.len(),
2622            1,
2623            "Expected span to have one link from follows_from relationship"
2624        );
2625
2626        assert!(
2627            links.contains(&span1_id),
2628            "Link should point to the correct source span"
2629        );
2630    }
2631
2632    #[test]
2633    fn follows_from_multiple_links_with_context_activation() {
2634        follows_from_multiple_links_impl(true);
2635    }
2636
2637    #[test]
2638    fn follows_from_multiple_links_no_context_activation() {
2639        follows_from_multiple_links_impl(false);
2640    }
2641
2642    fn follows_from_multiple_links_impl(context_activation: bool) {
2643        use crate::OpenTelemetrySpanExt;
2644        let mut tracer = TestTracer::default();
2645        let subscriber = tracing_subscriber::registry().with(
2646            layer()
2647                .with_tracer(tracer.clone())
2648                .with_context_activation(context_activation),
2649        );
2650
2651        let (span1_id, span2_id) = tracing::subscriber::with_default(subscriber, || {
2652            let span3 = tracing::debug_span!("span3");
2653            let span2 = tracing::debug_span!("span2");
2654            let span1 = tracing::debug_span!("span1");
2655
2656            // Establish multiple follows_from relationships
2657            span3.follows_from(&span1);
2658            span3.follows_from(&span2);
2659
2660            // Enter span3 to ensure it's exported
2661            let _guard = span3.enter();
2662
2663            // Get span IDs for later verification
2664            (
2665                span1.context().span().span_context().span_id(),
2666                span2.context().span().span_context().span_id(),
2667            )
2668        });
2669
2670        let spans = tracer.spans();
2671        // Check that all three spans are exported
2672        assert_eq!(spans.len(), 3, "Expected three spans to be exported");
2673        assert!(spans.iter().any(|span| span.name == "span1"));
2674        assert!(spans.iter().any(|span| span.name == "span2"));
2675        let span3 = spans
2676            .iter()
2677            .find(|span| span.name == "span3")
2678            .expect("Expected span3 to be exported");
2679
2680        // Collect span3 links
2681        let links = span3
2682            .links
2683            .iter()
2684            .map(|link| link.span_context.span_id())
2685            .collect::<Vec<_>>();
2686
2687        // Verify that span3 has multiple links and they point to the correct spans
2688        assert_eq!(
2689            links.len(),
2690            2,
2691            "Expected span to have two links from follows_from relationships"
2692        );
2693
2694        // Verify that the links point to the correct spans in the correct order
2695        assert!(
2696            links[0] == span1_id && links[1] == span2_id,
2697            "Links should point to the correct source spans"
2698        );
2699    }
2700
2701    #[test]
2702    fn context_activation_disabled() {
2703        use tracing::span;
2704
2705        let mut tracer = TestTracer::default();
2706        let subscriber = tracing_subscriber::registry().with(
2707            layer()
2708                .with_tracer(tracer.clone())
2709                .with_context_activation(false),
2710        );
2711
2712        tracing::subscriber::with_default(subscriber, || {
2713            // Add a value to the current OpenTelemetry context
2714            let _outer_guard =
2715                OtelContext::attach(OtelContext::default().with_value(ValueA("outer")));
2716            assert_eq!(OtelContext::current().get(), Some(&ValueA("outer")));
2717
2718            let root = span!(tracing::Level::TRACE, "tokio-tracing-span-parent");
2719
2720            // Drop the guard to ensure the context is cleared
2721            drop(_outer_guard);
2722            assert!(OtelContext::current().get::<ValueA>().is_none());
2723
2724            // Enter the root span - with context activation disabled,
2725            // the context should NOT be propagated
2726            let _enter_root = root.enter();
2727            assert!(OtelContext::current().get::<ValueA>().is_none());
2728
2729            // Add another value to the current OpenTelemetry context
2730            let _inner_guard =
2731                OtelContext::attach(OtelContext::current_with_value(ValueB("inner")));
2732            assert!(OtelContext::current().get::<ValueA>().is_none());
2733            assert_eq!(OtelContext::current().get(), Some(&ValueB("inner")));
2734
2735            let child = span!(tracing::Level::TRACE, "tokio-tracing-span-child");
2736
2737            // Drop the guard to ensure the context is reverted
2738            drop(_inner_guard);
2739            assert!(OtelContext::current().get::<ValueA>().is_none());
2740            assert!(OtelContext::current().get::<ValueB>().is_none());
2741
2742            // Enter the child span - with context activation disabled,
2743            // the context should NOT be propagated
2744            let _enter_child = child.enter();
2745            assert!(OtelContext::current().get::<ValueA>().is_none());
2746            assert!(OtelContext::current().get::<ValueB>().is_none());
2747        });
2748
2749        // Verify spans were still created and exported
2750        let spans = tracer.spans();
2751        assert_eq!(spans.len(), 2);
2752        assert!(spans
2753            .iter()
2754            .any(|span| span.name == "tokio-tracing-span-parent"));
2755        assert!(spans
2756            .iter()
2757            .any(|span| span.name == "tokio-tracing-span-child"));
2758    }
2759}