Skip to content

Commit 7f4409a

Browse files
Invalidate sample decision on set parent fix #150 (#153)
1 parent 9462de6 commit 7f4409a

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

src/span_ext.rs

+1
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ impl OpenTelemetrySpanExt for tracing::Span {
143143
get_context.with_context(subscriber, id, move |data, _tracer| {
144144
if let Some(cx) = cx.take() {
145145
data.parent_cx = cx;
146+
data.builder.sampling_result = None;
146147
}
147148
});
148149
}

tests/trace_state_propagation.rs

+44-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use opentelemetry::{
77
use opentelemetry_sdk::{
88
export::trace::{ExportResult, SpanData, SpanExporter},
99
propagation::{BaggagePropagator, TraceContextPropagator},
10-
trace::{Tracer, TracerProvider},
10+
trace::{Config, Sampler, Tracer, TracerProvider},
1111
};
1212
use std::collections::{HashMap, HashSet};
1313
use std::sync::{Arc, Mutex};
@@ -101,6 +101,49 @@ fn inject_context_into_outgoing_requests() {
101101
assert_carrier_attrs_eq(&carrier, &outgoing_req_carrier);
102102
}
103103

104+
#[test]
105+
fn sampling_decision_respects_new_parent() {
106+
// custom setup required due to ParentBased(AlwaysOff) sampler
107+
let exporter = TestExporter::default();
108+
let provider = TracerProvider::builder()
109+
.with_simple_exporter(exporter.clone())
110+
.with_config(
111+
Config::default().with_sampler(Sampler::ParentBased(Box::new(Sampler::AlwaysOff))),
112+
)
113+
.build();
114+
let tracer = provider.tracer("test");
115+
let subscriber = tracing_subscriber::registry().with(layer().with_tracer(tracer.clone()));
116+
117+
// set up remote sampled headers
118+
let sampled_headers = HashMap::from([(
119+
"traceparent".to_string(),
120+
"00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01".to_string(),
121+
)]);
122+
let remote_sampled_cx = TraceContextPropagator::new().extract(&sampled_headers);
123+
let root_span = tracer.start_with_context("root_span", &remote_sampled_cx);
124+
125+
tracing::subscriber::with_default(subscriber, || {
126+
let child = tracing::debug_span!("child");
127+
child.context(); // force a sampling decision
128+
child.set_parent(Context::current_with_span(root_span));
129+
});
130+
131+
drop(provider); // flush all spans
132+
133+
// assert new parent-based sampling decision
134+
let spans = exporter.0.lock().unwrap();
135+
assert_eq!(spans.len(), 2, "Expected 2 spans, got {}", spans.len());
136+
assert!(
137+
spans[0].span_context.is_sampled(),
138+
"Root span should be sampled"
139+
);
140+
assert_eq!(
141+
spans[1].span_context.is_sampled(),
142+
spans[0].span_context.is_sampled(),
143+
"Child span should respect parent sampling decision"
144+
);
145+
}
146+
104147
fn assert_shared_attrs_eq(sc_a: &SpanContext, sc_b: &SpanContext) {
105148
assert_eq!(sc_a.trace_id(), sc_b.trace_id());
106149
assert_eq!(sc_a.trace_state(), sc_b.trace_state());

0 commit comments

Comments
 (0)