Skip to content

What this does not do

Things people reasonably expect from a telemetry crate that this one does not provide. Where there is a workaround it is named; where the answer is simply "no", it says so.

There is no batching, queueing or retry

record awaits the sink's emit and returns its result. HttpSink makes one POST per event and waits for it. If the collector is slow, the caller waits, bounded by the configured timeout. If the POST fails, the event is gone — nothing is queued, retried or backed off.

Two workarounds, depending on what you need. Write to a FileSink and ship the file with something built for the job. Or wrap a sink in your own implementation that buffers and flushes on a schedule — the trait is small enough that this is a short piece of code.

OtlpSink is the exception: the OpenTelemetry SDK batches behind it. That is also why its emit cannot tell you whether the export worked.

There is no sampling or rate limiting

Every record call on an Enabled context produces an event. There is no sample rate, no per-event budget and no de-duplication. A loop that records per iteration will emit per iteration.

Nothing is collected automatically

The crate records what you tell it to record. It does not hook a CLI framework, wrap a command dispatcher, capture panics, time anything, or derive event names from the call site. Every event exists because a record call was written.

That also means event naming is entirely yours. command.invoke and tool.start are conventions used in the examples, not values the crate knows about.

It does not read configuration or environment variables

TelemetryContext takes a CollectionPolicy from the caller. The crate does not read a config file, an environment variable or a CLI flag, and the consent module does not choose a path — you pass it one.

Tools built on rtb-cli get that layer from the CLI runtime, which resolves a policy from the consent file and an environment variable and ships telemetry status / enable / disable / reset. Tools not built on it wire their own.

The crate persists a decision. Asking for it — the wording, the timing, whether to prompt on first run at all — is the tool's job. Nothing here will interact with a user.

There is no data-deletion path

consent::reset deletes the decision, so the tool goes back to "never asked". It does not delete events already written to a FileSink, already POSTed to an endpoint, or already exported to a collector. There is no "delete everything about me" call, because the crate has no idea where the data ended up — that is the sink's business, and for remote sinks it is the backend operator's.

A tool that promises a deletion path has to implement it against whatever it configured as a destination.

The policy cannot be changed on a built context

CollectionPolicy is fixed at build(). There is no setter, and nothing watches the consent file for changes. A tool that lets a user opt out mid-run rebuilds the context (or drops it) to make that take effect.

One context has exactly one sink

TelemetryContext holds a single Arc<dyn TelemetrySink>. You cannot attach two, so "write to a file and POST to a collector" is not a supported configuration out of the box. Implement a fan-out sink that owns both and forwards emit to each — and decide there what happens when one of them fails.

FileSink never rotates or prunes

The file grows for as long as the tool keeps recording. There is no size cap, no rotation, no retention window and no compression. If it is going to run for a long time on a machine you do not control, put it somewhere the operating system already manages, or rotate it yourself.

Line integrity is process-local

Concurrent emit calls within one process cannot interleave. Two processes appending to the same file can, once an event exceeds 4 KiB. See Why FileSink holds a lock. Give each process its own file.

OTLP export is logs only, and OTLP/HTTP is broken in 0.7.3

OtlpSink emits OpenTelemetry log records. It does not produce traces or metrics, and it is not a service-observability layer — this crate is product analytics about a user's tool, not instrumentation of a running service.

The OTLP/HTTP transport does not currently work: an endpoint that routes to it panics inside the SDK's exporter thread and exports nothing. Use grpc://, grpcs:// or a :4317 endpoint. The detail, with the exact failure, is in Sinks.

Attributes are never redacted

Event::attrs values ship exactly as you set them, to every sink. Only args and err_msg are scrubbed, and only by the sinks that write off-process. See Where redaction applies.

There is no blocking API

record, record_with_attrs and flush are async and want a Tokio runtime. There is no synchronous wrapper, and calling them from a non-async context means providing a runtime yourself.

The event JSON is not a frozen schema

Event is #[non_exhaustive] and new fields can appear in a minor release. Anything parsing the JSON should ignore unknown fields rather than reject them. Attribute key order is not stable between runs either — it is a HashMap.