Skip to content

Commit c18a70e

Browse files
committed
chore: update SpanRef context access based on feedback
1 parent f62c2bf commit c18a70e

File tree

6 files changed

+162
-185
lines changed

6 files changed

+162
-185
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ opentelemetry_sdk = { version = "0.31.0", default-features = false, features = [
2929
] }
3030
tracing = { version = "0.1.35", default-features = false, features = ["std"] }
3131
tracing-core = "0.1.28"
32-
tracing-subscriber = { version = "0.3.0", default-features = false, features = [
32+
tracing-subscriber = { version = "0.3.22", default-features = false, features = [
3333
"registry",
3434
"std",
3535
] }

examples/otel_context.rs

Lines changed: 31 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@
44
use opentelemetry::trace::{TraceContextExt, TracerProvider as _};
55
use opentelemetry_sdk::trace::SdkTracerProvider;
66
use opentelemetry_stdout as stdout;
7-
use std::sync::{Arc, Mutex, RwLock};
7+
use std::sync::{Arc, Mutex, OnceLock};
88
use tracing::{debug, info, span, warn, Subscriber};
99
use tracing::{dispatcher::WeakDispatch, level_filters::LevelFilter, Dispatch};
10-
use tracing_opentelemetry::{layer, OpenTelemetryContext};
10+
use tracing_opentelemetry::{get_otel_context, layer};
1111
use tracing_subscriber::layer::Context;
1212
use tracing_subscriber::prelude::*;
1313
use tracing_subscriber::registry::LookupSpan;
1414
use tracing_subscriber::Layer;
1515

1616
/// A custom layer that demonstrates how to use OpenTelemetryContext
1717
/// to extract OpenTelemetry contexts from span extensions.
18-
#[derive(Clone)]
18+
#[derive(Clone, Default)]
1919
struct SpanAnalysisLayer {
2020
/// Store span analysis results for demonstration
2121
analysis_results: Arc<Mutex<Vec<SpanAnalysis>>>,
2222
/// Weak reference to the dispatcher for context extraction
23-
dispatch: Arc<RwLock<Option<WeakDispatch>>>,
23+
dispatch: Arc<OnceLock<WeakDispatch>>,
2424
}
2525

2626
#[derive(Debug, Clone)]
@@ -32,13 +32,6 @@ struct SpanAnalysis {
3232
}
3333

3434
impl SpanAnalysisLayer {
35-
fn new() -> Self {
36-
Self {
37-
analysis_results: Arc::new(Mutex::new(Vec::new())),
38-
dispatch: Arc::new(RwLock::new(None)),
39-
}
40-
}
41-
4235
fn get_analysis_results(&self) -> Vec<SpanAnalysis> {
4336
self.analysis_results.lock().unwrap().clone()
4437
}
@@ -68,46 +61,23 @@ impl SpanAnalysisLayer {
6861
}
6962
}
7063
}
71-
72-
fn get_weak_dispatch(&self, get_default: bool) -> Option<WeakDispatch> {
73-
let read_guard = self.dispatch.read().unwrap();
74-
match read_guard.as_ref() {
75-
Some(weak_dispatch) => Some(weak_dispatch.clone()),
76-
// Note: This workaround is needed until https://github.com/tokio-rs/tracing/pull/3379
77-
// is merged and released. It should really be handled in on_register_dispatch
78-
None => {
79-
if !get_default {
80-
None
81-
} else {
82-
drop(read_guard);
83-
let mut dispatch = self.dispatch.write().unwrap();
84-
let weak_dispatch = Dispatch::default().downgrade();
85-
*dispatch = Some(weak_dispatch.clone());
86-
Some(weak_dispatch)
87-
}
88-
}
89-
}
90-
}
9164
}
9265

9366
impl<S> Layer<S> for SpanAnalysisLayer
9467
where
9568
S: Subscriber + for<'span> LookupSpan<'span>,
9669
{
70+
fn on_register_dispatch(&self, subscriber: &Dispatch) {
71+
let _ = self.dispatch.set(subscriber.downgrade());
72+
}
73+
9774
fn on_new_span(
9875
&self,
9976
attrs: &tracing::span::Attributes<'_>,
10077
id: &tracing::span::Id,
10178
ctx: Context<'_, S>,
10279
) {
103-
// Get the weak dispatch reference.
104-
//
105-
// Note: We can't use the Dispatch::default() workaround described above here since this
106-
// method is called from inside a dispatcher::get_default block, and such calls can't be
107-
// nested so we would get the global dispatcher instead, which can't downcast to the right
108-
// types when extracting the OpenTelemetry context. This also means that we will miss
109-
// analyzing the first span that is created 🤷🏼‍♂️
110-
let Some(weak_dispatch) = self.get_weak_dispatch(false) else {
80+
let Some(weak_dispatch) = self.dispatch.get() else {
11181
return;
11282
};
11383

@@ -116,46 +86,39 @@ where
11686
// This is the key functionality: using OpenTelemetryContext
11787
// to extract the OpenTelemetry context from span extensions
11888
let mut extensions = span_ref.extensions_mut();
119-
if let Some(otel_context) =
120-
OpenTelemetryContext::context(&mut extensions, &weak_dispatch.upgrade())
121-
{
122-
self.analyze_span_context(attrs.metadata().name(), &otel_context);
123-
} else {
124-
println!(
125-
"⚠️ Could not extract OpenTelemetry context for span '{}'",
126-
attrs.metadata().name()
127-
);
89+
if let Some(dispatch) = weak_dispatch.upgrade() {
90+
if let Some(otel_context) = get_otel_context(&mut extensions, &dispatch) {
91+
self.analyze_span_context(attrs.metadata().name(), &otel_context);
92+
} else {
93+
println!(
94+
"⚠️ Could not extract OpenTelemetry context for span '{}'",
95+
attrs.metadata().name()
96+
);
97+
}
12898
}
12999
}
130100
}
131101

132102
fn on_enter(&self, id: &tracing::span::Id, ctx: Context<'_, S>) {
133-
if let Some(weak_dispatch) = self.get_weak_dispatch(true) {
103+
if let Some(weak_dispatch) = self.dispatch.get() {
134104
if let Some(span_ref) = ctx.span(id) {
135105
let mut extensions = span_ref.extensions_mut();
136-
if let Some(otel_context) =
137-
OpenTelemetryContext::context(&mut extensions, &weak_dispatch.upgrade())
138-
{
139-
let span = otel_context.span();
140-
let span_context = span.span_context();
141-
if span_context.is_valid() {
142-
println!(
143-
"📍 Entering span with trace_id: {:032x}, span_id: {:016x}",
144-
span_context.trace_id(),
145-
span_context.span_id()
146-
);
106+
if let Some(dispatch) = weak_dispatch.upgrade() {
107+
if let Some(otel_context) = get_otel_context(&mut extensions, &dispatch) {
108+
let span = otel_context.span();
109+
let span_context = span.span_context();
110+
if span_context.is_valid() {
111+
println!(
112+
"📍 Entering span with trace_id: {:032x}, span_id: {:016x}",
113+
span_context.trace_id(),
114+
span_context.span_id()
115+
);
116+
}
147117
}
148118
}
149119
}
150120
}
151121
}
152-
153-
fn on_register_dispatch(&self, subscriber: &tracing::Dispatch) {
154-
// Note: This does not work for Layer until https://github.com/tokio-rs/tracing/pull/3379
155-
// is merged and released, since `on_register_dispatch` is never called.
156-
let mut dispatch = self.dispatch.write().unwrap();
157-
*dispatch = Some(subscriber.clone().downgrade());
158-
}
159122
}
160123

161124
fn setup_tracing() -> (impl Subscriber, SdkTracerProvider, SpanAnalysisLayer) {
@@ -166,7 +129,7 @@ fn setup_tracing() -> (impl Subscriber, SdkTracerProvider, SpanAnalysisLayer) {
166129
let tracer = provider.tracer("span_ref_ext_example");
167130

168131
// Create our custom analysis layer
169-
let analysis_layer = SpanAnalysisLayer::new();
132+
let analysis_layer = SpanAnalysisLayer::default();
170133

171134
// Build the subscriber with multiple layers:
172135
// 1. OpenTelemetry layer for trace export

src/layer.rs

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,11 @@ pub(crate) struct WithContext {
112112

113113
///
114114
/// Ensures the given SpanId has been activated - that is, created in the OTel side of things,
115-
/// and had its SpanBuilder consumed - and then provides access to the OtelData associated with it.
115+
/// and had its SpanBuilder consumed - and then provides access to the OTel Context associated with it.
116116
///
117117
#[allow(clippy::type_complexity)]
118-
pub(crate) with_activated_context_extensions:
119-
fn(&tracing::Dispatch, &mut ExtensionsMut<'_>, f: &mut dyn FnMut(&mut OtelData)),
118+
pub(crate) with_activated_otel_context:
119+
fn(&tracing::Dispatch, &mut ExtensionsMut<'_>, f: &mut dyn FnMut(&OtelContext)),
120120
}
121121

122122
impl WithContext {
@@ -152,13 +152,13 @@ impl WithContext {
152152
/// and had its SpanBuilder consumed - and then provides access to the OtelData associated with it.
153153
///
154154
#[allow(clippy::type_complexity)]
155-
pub(crate) fn with_activated_context_extensions(
155+
pub(crate) fn with_activated_otel_context(
156156
&self,
157157
dispatch: &tracing::Dispatch,
158158
extensions: &mut ExtensionsMut<'_>,
159-
mut f: impl FnMut(&mut OtelData),
159+
mut f: impl FnMut(&OtelContext),
160160
) {
161-
(self.with_activated_context_extensions)(dispatch, extensions, &mut f)
161+
(self.with_activated_otel_context)(dispatch, extensions, &mut f)
162162
}
163163
}
164164

@@ -652,7 +652,7 @@ where
652652
with_context: WithContext {
653653
with_context: Self::get_context,
654654
with_activated_context: Self::get_activated_context,
655-
with_activated_context_extensions: Self::get_activated_context_extensions,
655+
with_activated_otel_context: Self::get_activated_otel_context,
656656
},
657657
_registry: marker::PhantomData,
658658
}
@@ -708,8 +708,8 @@ where
708708
with_context: WithContext {
709709
with_context: OpenTelemetryLayer::<S, Tracer>::get_context,
710710
with_activated_context: OpenTelemetryLayer::<S, Tracer>::get_activated_context,
711-
with_activated_context_extensions:
712-
OpenTelemetryLayer::<S, Tracer>::get_activated_context_extensions,
711+
with_activated_otel_context:
712+
OpenTelemetryLayer::<S, Tracer>::get_activated_otel_context,
713713
},
714714
_registry: self._registry,
715715
// cannot use ``..self` here due to different generics
@@ -967,6 +967,18 @@ where
967967
}
968968
}
969969

970+
/// Retrieves the OpenTelemetry data for a span and activates its context before calling
971+
/// the provided function.
972+
///
973+
/// This function retrieves the span from the subscriber's registry using the provided
974+
/// span ID, activates the OTel `Context` in the span's `OtelData` if present, and then
975+
/// applies the callback function `f` to the `OtelData`.
976+
///
977+
/// # Parameters
978+
///
979+
/// * `dispatch` - The tracing dispatch to downcast and retrieve the span from
980+
/// * `id` - The span ID to look up in the registry
981+
/// * `f` - The closure to invoke with mutable access to the span's `OtelData`
970982
fn get_activated_context(
971983
dispatch: &tracing::Dispatch,
972984
id: &span::Id,
@@ -984,6 +996,34 @@ where
984996
Self::get_activated_context_extensions(dispatch, &mut extensions, f)
985997
}
986998

999+
/// Retrieves the activated OpenTelemetry context from a span's extensions and passes it
1000+
/// to the provided function.
1001+
///
1002+
/// This method activates the context and extracts the current OTel `Context` from the
1003+
/// `OtelData` state if present, and then applies the callback function `f` to a reference
1004+
/// to the OTel `Context`.
1005+
///
1006+
/// # Parameters
1007+
///
1008+
/// * `dispatch` - The tracing dispatch to downcast to the `OpenTelemetryLayer`
1009+
/// * `extensions` - Mutable reference to the span's extensions containing `OtelData`
1010+
/// * `f` - The closure to invoke with a reference to the OTel `Context`
1011+
fn get_activated_otel_context(
1012+
dispatch: &tracing::Dispatch,
1013+
extensions: &mut ExtensionsMut<'_>,
1014+
f: &mut dyn FnMut(&OtelContext),
1015+
) {
1016+
Self::get_activated_context_extensions(
1017+
dispatch,
1018+
extensions,
1019+
&mut |otel_data: &mut OtelData| {
1020+
if let OtelDataState::Context { current_cx } = &otel_data.state {
1021+
f(current_cx)
1022+
}
1023+
},
1024+
);
1025+
}
1026+
9871027
fn get_activated_context_extensions(
9881028
dispatch: &tracing::Dispatch,
9891029
extensions: &mut ExtensionsMut<'_>,

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ mod metrics;
115115

116116
/// Implementation of the trace::Layer as a source of OpenTelemetry data.
117117
mod layer;
118-
/// OpenTelemetryContext which enables OpenTelemetry context extraction from span extensions.
118+
/// Function which enables OpenTelemetry context extraction from span extensions.
119119
mod otel_context;
120120
/// Span extension which enables OpenTelemetry context management.
121121
mod span_ext;
@@ -129,7 +129,7 @@ pub use layer::{layer, FilteredOpenTelemetryLayer, OpenTelemetryLayer};
129129
#[cfg(feature = "metrics")]
130130
pub use metrics::MetricsLayer;
131131
use opentelemetry::trace::TraceContextExt as _;
132-
pub use otel_context::OpenTelemetryContext;
132+
pub use otel_context::get_otel_context;
133133
pub use span_ext::{OpenTelemetrySpanExt, SetParentError};
134134

135135
/// Per-span OpenTelemetry data tracked by this crate.

0 commit comments

Comments
 (0)