#[non_exhaustive]pub struct TraceGrouping {
pub session_id: Option<String>,
pub end_user_hash: Option<String>,
pub tags: Vec<String>,
pub environment: Option<String>,
pub release: Option<String>,
}Expand description
Vendor-neutral grouping of spans: which session, which end user, which tags, which environment, which release.
LLM observability backends filter at the level of the individual span, not only at the trace root, so the grouping has to reach every span rather than sit on the first one. Two ways to make that happen:
- Without the
otelfeature,TraceGrouping::stampfills the grouping fields — which every span this crate opens declares empty — on whichever span you hand it, andTraceGrouping::scope_spanopens a parent span that carries them for a subscriber that flattens ancestors. - With the
otelfeature,crate::otel::attach_groupingputs the same values in OpenTelemetry baggage on the current context, where a baggage-copying span processor in the application’s SDK setup stamps them onto every span that starts underneath. The processor itself lives in the adopter’s code because it needsopentelemetry_sdk, which this crate does not depend on;crate::otel::grouping_from_baggagegives it the key/values to copy.
The end-user reference is always a digest — build it with
TraceGrouping::with_account, which hashes the account id, or supply your
own digest with TraceGrouping::with_end_user_hash. There is no
constructor that takes a raw account or user identifier.
A backend that insists on its own attribute names is a renaming function
over TraceGrouping::fields in the adopter’s code, not something this
crate hardcodes.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.session_id: Option<String>The session, recorded as session.id. Turnframe uses the conversation.
end_user_hash: Option<String>Digest of the end user, recorded as user.id. Never a raw identifier.
Free-form grouping labels the application chose.
environment: Option<String>Deployment environment, e.g. production.
release: Option<String>Release or build of the running service.
Implementations§
Source§impl TraceGrouping
impl TraceGrouping
Sourcepub fn for_conversation(conversation_id: ConversationId) -> Self
pub fn for_conversation(conversation_id: ConversationId) -> Self
Groups spans by conversation, which is the session a backend shows.
Sourcepub fn with_account(self, account_id: &AccountId) -> Self
pub fn with_account(self, account_id: &AccountId) -> Self
Adds the end user as the digest of an account id. The raw id is hashed
by account_hash and never stored on the grouping.
Sourcepub fn with_end_user_hash(self, hash: impl Into<String>) -> Self
pub fn with_end_user_hash(self, hash: impl Into<String>) -> Self
Adds an end-user reference the caller has already hashed.
Sourcepub fn with_environment(self, environment: impl Into<String>) -> Self
pub fn with_environment(self, environment: impl Into<String>) -> Self
Sets the deployment environment.
Sourcepub fn with_release(self, release: impl Into<String>) -> Self
pub fn with_release(self, release: impl Into<String>) -> Self
Sets the release or build.
Sourcepub fn fields(&self) -> Vec<(&'static str, String)>
pub fn fields(&self) -> Vec<(&'static str, String)>
The grouping as (attribute key, value) pairs in a stable order,
omitting what is unset. Testable without a subscriber, and the set an
adopter renames for a backend with its own spelling.
Sourcepub fn stamp(&self, span: &Span)
pub fn stamp(&self, span: &Span)
Records the grouping on span.
Every span this crate opens declares the grouping fields empty, so this fills them in. Recording on a span that did not declare them is a no-op rather than an error.
Sourcepub fn stamp_current(&self)
pub fn stamp_current(&self)
Records the grouping on the span that is currently entered.
Sourcepub fn scope_span(&self) -> Span
pub fn scope_span(&self) -> Span
Opens a span that carries the grouping and becomes the parent of every span opened while it is entered.
use turnframe_core::ids::{AccountId, ConversationId};
use turnframe_telemetry::tracing::TraceGrouping;
let grouping = TraceGrouping::for_conversation(ConversationId::nil())
.with_account(&AccountId::from("acct-1"))
.with_environment("production")
.with_release("v0.1.0")
.with_tag("trip");
let span = grouping.scope_span();
let _entered = span.enter();Trait Implementations§
Source§impl Clone for TraceGrouping
impl Clone for TraceGrouping
Source§impl Debug for TraceGrouping
impl Debug for TraceGrouping
Source§impl Default for TraceGrouping
impl Default for TraceGrouping
impl Eq for TraceGrouping
Source§impl PartialEq for TraceGrouping
impl PartialEq for TraceGrouping
impl StructuralPartialEq for TraceGrouping
Auto Trait Implementations§
impl Freeze for TraceGrouping
impl RefUnwindSafe for TraceGrouping
impl Send for TraceGrouping
impl Sync for TraceGrouping
impl Unpin for TraceGrouping
impl UnsafeUnpin for TraceGrouping
impl UnwindSafe for TraceGrouping
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.