TelemetryContext and its builder¶
TelemetryContext is the handle tool code records events through. It is
cheap to clone: clones share the same sink, machine ID and policy through
Arc, so passing it around a program does not duplicate any of them.
Builder fields, defaults and requirements¶
TelemetryContext::builder() returns a TelemetryContextBuilder. Every
setter takes self and returns Self, so calls chain.
| Method | Type | Default | Required |
|---|---|---|---|
.tool(…) |
impl Into<String> |
none | Always |
.tool_version(…) |
impl Into<String> |
none | Always |
.salt(…) |
impl Into<String> |
none | Only when policy is Enabled |
.sink(…) |
Arc<dyn TelemetrySink> |
Arc::new(NoopSink) |
No |
.policy(…) |
CollectionPolicy |
CollectionPolicy::Disabled |
No |
A context built with the defaults (no sink, no policy) collects nothing and sends nothing. That is deliberate; see Two-level opt-in.
What happens when a required field is missing¶
build() panics rather than returning an error, because a missing tool name
is a programming mistake in the calling tool, not a runtime condition its
users can hit. The panic message names the missing field:
TelemetryContextBuilder: tool is required
TelemetryContextBuilder: tool_version is required
TelemetryContextBuilder: salt is required when policy is Enabled
The salt is only consulted when the policy is Enabled. A Disabled
context built without a salt is valid, and building it derives no machine
ID at all. Nothing on the host is read.
CollectionPolicy: the runtime switch¶
Disabled is the Default. ConsentState converts into it with From, so
policy(consent.state.into()) is the usual wiring. See
the consent file.
ctx.policy() returns the current value. The policy is fixed at build time:
there is no setter on a built context, so a tool that lets a user toggle
consent mid-run rebuilds the context.
What record does¶
pub async fn record(&self, event_name: &str) -> Result<(), TelemetryError>
pub async fn record_with_attrs(&self, event_name: &str, attrs: HashMap<String, String>)
-> Result<(), TelemetryError>
pub async fn flush(&self) -> Result<(), TelemetryError>
Under CollectionPolicy::Disabled all three return Ok(()) immediately. No
Event is constructed, no attribute map is read, and the sink is never
called, not even for flush.
Under Enabled, record builds an Event stamped with the current UTC
time and awaits sink.emit(&event). The sink's error is returned to the
caller unchanged; the crate does not retry, buffer or swallow it. Whether a
failed telemetry write should fail the surrounding command is the calling
tool's decision, and the usual answer is no.
record_with_attrs replaces the event's attribute map wholesale with the
map you pass. Attributes are not redacted; see
Where redaction applies.
What flush does¶
flush delegates to the sink's flush, whose default implementation is a
no-op. Only OtlpSink overrides it, and for OtlpSink the flush is where
export failures actually surface, because emit returns Ok(()) regardless. See
Sinks.
Async, and the runtime it needs¶
record, record_with_attrs and flush are async, and FileSink uses
Tokio's filesystem API, so the crate needs a Tokio runtime to be useful.
There is no blocking convenience wrapper.
Thread-safety¶
TelemetryContext is Clone + Send + Sync + 'static, and the
TelemetrySink trait requires Send + Sync + 'static of every
implementation. Sharing one context across tasks is the intended usage.
Debug output does not leak the machine ID¶
The hand-written Debug implementation prints the tool, the tool version,
the policy, machine_id_len (the length, not the value) and
"<dyn TelemetrySink>" in place of the sink. Debug-printing a context in a
log line will not put a machine identity in that log line.