Skip to content

Commit 0fb652b

Browse files
bantonssonmladedav
authored andcommitted
chore: update SpanRef context access based on feedback
1 parent d8f4699 commit 0fb652b

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
@@ -27,7 +27,7 @@ opentelemetry = { version = "0.31.0", default-features = false, features = [
2727

2828
tracing = { version = "0.1.35", default-features = false, features = ["std"] }
2929
tracing-core = "0.1.28"
30-
tracing-subscriber = { version = "0.3.0", default-features = false, features = [
30+
tracing-subscriber = { version = "0.3.22", default-features = false, features = [
3131
"registry",
3232
"std",
3333
] }

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
@@ -121,11 +121,11 @@ pub(crate) struct WithContext {
121121

122122
///
123123
/// Ensures the given SpanId has been activated - that is, created in the OTel side of things,
124-
/// and had its SpanBuilder consumed - and then provides access to the OtelData associated with it.
124+
/// and had its SpanBuilder consumed - and then provides access to the OTel Context associated with it.
125125
///
126126
#[allow(clippy::type_complexity)]
127-
pub(crate) with_activated_context_extensions:
128-
fn(&tracing::Dispatch, &mut ExtensionsMut<'_>, f: &mut dyn FnMut(&mut OtelData)),
127+
pub(crate) with_activated_otel_context:
128+
fn(&tracing::Dispatch, &mut ExtensionsMut<'_>, f: &mut dyn FnMut(&OtelContext)),
129129
}
130130

131131
impl WithContext {
@@ -161,13 +161,13 @@ impl WithContext {
161161
/// and had its SpanBuilder consumed - and then provides access to the OtelData associated with it.
162162
///
163163
#[allow(clippy::type_complexity)]
164-
pub(crate) fn with_activated_context_extensions(
164+
pub(crate) fn with_activated_otel_context(
165165
&self,
166166
dispatch: &tracing::Dispatch,
167167
extensions: &mut ExtensionsMut<'_>,
168-
mut f: impl FnMut(&mut OtelData),
168+
mut f: impl FnMut(&OtelContext),
169169
) {
170-
(self.with_activated_context_extensions)(dispatch, extensions, &mut f)
170+
(self.with_activated_otel_context)(dispatch, extensions, &mut f)
171171
}
172172
}
173173

@@ -661,7 +661,7 @@ where
661661
with_context: WithContext {
662662
with_context: Self::get_context,
663663
with_activated_context: Self::get_activated_context,
664-
with_activated_context_extensions: Self::get_activated_context_extensions,
664+
with_activated_otel_context: Self::get_activated_otel_context,
665665
},
666666
_registry: marker::PhantomData,
667667
}
@@ -717,8 +717,8 @@ where
717717
with_context: WithContext {
718718
with_context: OpenTelemetryLayer::<S, Tracer>::get_context,
719719
with_activated_context: OpenTelemetryLayer::<S, Tracer>::get_activated_context,
720-
with_activated_context_extensions:
721-
OpenTelemetryLayer::<S, Tracer>::get_activated_context_extensions,
720+
with_activated_otel_context:
721+
OpenTelemetryLayer::<S, Tracer>::get_activated_otel_context,
722722
},
723723
_registry: self._registry,
724724
// cannot use ``..self` here due to different generics
@@ -976,6 +976,18 @@ where
976976
}
977977
}
978978

979+
/// Retrieves the OpenTelemetry data for a span and activates its context before calling
980+
/// the provided function.
981+
///
982+
/// This function retrieves the span from the subscriber's registry using the provided
983+
/// span ID, activates the OTel `Context` in the span's `OtelData` if present, and then
984+
/// applies the callback function `f` to the `OtelData`.
985+
///
986+
/// # Parameters
987+
///
988+
/// * `dispatch` - The tracing dispatch to downcast and retrieve the span from
989+
/// * `id` - The span ID to look up in the registry
990+
/// * `f` - The closure to invoke with mutable access to the span's `OtelData`
979991
fn get_activated_context(
980992
dispatch: &tracing::Dispatch,
981993
id: &span::Id,
@@ -993,6 +1005,34 @@ where
9931005
Self::get_activated_context_extensions(dispatch, &mut extensions, f)
9941006
}
9951007

1008+
/// Retrieves the activated OpenTelemetry context from a span's extensions and passes it
1009+
/// to the provided function.
1010+
///
1011+
/// This method activates the context and extracts the current OTel `Context` from the
1012+
/// `OtelData` state if present, and then applies the callback function `f` to a reference
1013+
/// to the OTel `Context`.
1014+
///
1015+
/// # Parameters
1016+
///
1017+
/// * `dispatch` - The tracing dispatch to downcast to the `OpenTelemetryLayer`
1018+
/// * `extensions` - Mutable reference to the span's extensions containing `OtelData`
1019+
/// * `f` - The closure to invoke with a reference to the OTel `Context`
1020+
fn get_activated_otel_context(
1021+
dispatch: &tracing::Dispatch,
1022+
extensions: &mut ExtensionsMut<'_>,
1023+
f: &mut dyn FnMut(&OtelContext),
1024+
) {
1025+
Self::get_activated_context_extensions(
1026+
dispatch,
1027+
extensions,
1028+
&mut |otel_data: &mut OtelData| {
1029+
if let OtelDataState::Context { current_cx } = &otel_data.state {
1030+
f(current_cx)
1031+
}
1032+
},
1033+
);
1034+
}
1035+
9961036
fn get_activated_context_extensions(
9971037
dispatch: &tracing::Dispatch,
9981038
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)