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 the 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 — 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.