pub struct GroupingSpanProcessor;Expand description
A span processor that copies the trace grouping out of OpenTelemetry baggage onto every span that starts underneath it.
LLM observability backends filter on each span, not only the trace root, so a
session.id on the turn’s first span leaves its children unattributable.
attach_grouping puts the grouping in baggage and this turns it into attributes as each
span starts; only the keys of crate::attrs::GROUPING_KEYS are copied, so an
application’s own baggage never leaks into telemetry. Hold the attach_grouping guard
for the whole turn: a span that already started cannot gain attributes.
use opentelemetry::trace::{Tracer, TracerProvider};
use opentelemetry_sdk::trace::SdkTracerProvider;
use turnframe_core::ids::{AccountId, ConversationId};
use turnframe_telemetry::otel::{GroupingSpanProcessor, attach_grouping};
use turnframe_telemetry::tracing::TraceGrouping;
let provider = SdkTracerProvider::builder()
.with_span_processor(GroupingSpanProcessor::new())
// .with_span_processor(your_exporting_processor)
.build();
let tracer = provider.tracer("turnframe");
let grouping = TraceGrouping::for_conversation(ConversationId::nil())
.with_account(&AccountId::from("acct-1"))
.with_environment("production");
// Attach first, then open spans: every span started while the guard is
// alive carries session.id, user.id, deployment.environment.name.
let _guard = attach_grouping(&grouping);
let mut span = tracer.start("turnframe.turn");
span.end();Implementations§
Trait Implementations§
Source§impl Clone for GroupingSpanProcessor
impl Clone for GroupingSpanProcessor
impl Copy for GroupingSpanProcessor
Source§impl Debug for GroupingSpanProcessor
impl Debug for GroupingSpanProcessor
Source§impl Default for GroupingSpanProcessor
impl Default for GroupingSpanProcessor
Source§impl SpanProcessor for GroupingSpanProcessor
impl SpanProcessor for GroupingSpanProcessor
Source§fn on_end(&self, _span: SpanData)
fn on_end(&self, _span: SpanData)
Nothing to do: the grouping was already stamped at on_start, which is
what the OpenTelemetry SDK asks for — a context read at on_end would
see whatever context happens to be active, not the span’s own.
Source§fn on_start(&self, span: &mut Span, cx: &Context)
fn on_start(&self, span: &mut Span, cx: &Context)
on_start is called when a Span is started. This method is called
synchronously on the thread that started the span, therefore it should
not block or throw exceptions.