Export to an OTLP collector¶
OtlpSink turns each event into one OpenTelemetry log record. It needs the
remote-sinks feature.
Use a gRPC endpoint¶
use std::sync::Arc;
use std::time::Duration;
use rtb_telemetry::{OtlpSink, OtlpSinkConfig};
let sink = Arc::new(OtlpSink::new(OtlpSinkConfig {
endpoint: "grpc://collector.internal:4317".into(),
headers: vec![],
timeout: Duration::from_secs(10),
resource_attrs: vec![("service.name".into(), "mytool".into())],
})?);
Use grpc:// or grpcs://, or an http(s):// URL containing :4317.
Do not use an OTLP/HTTP endpoint: in 0.7.3 that transport panics inside
the SDK's exporter thread and exports nothing. The failure and the versions
it was tested against are in
Sinks.
Almost every collector accepts OTLP/gRPC on 4317, so this is usually a
one-word change.
Transport is inferred from the endpoint — there is no explicit setting. The full rule is in Sinks.
Authenticate, or address a tenant¶
use secrecy::SecretString;
headers: vec![
("authorization".into(), SecretString::from(format!("Bearer {token}"))),
("x-scope-orgid".into(), SecretString::from("team-a".to_string())),
],
Header values are SecretString, so they stay out of Debug output. On
the gRPC transport they become request metadata; an invalid header name or
value is rejected when the sink is built, as TelemetryError::Otlp.
Check that the export actually worked¶
emit returns Ok(()) whatever happens — including when the collector is
refusing connections. The only way to find out is to flush:
telemetry.record("command.invoke").await?;
if let Err(err) = telemetry.flush().await {
tracing::warn!(%err, "telemetry export failed");
}
A dead collector produces something like:
OTLP telemetry sink error: flush: Operation failed: errs: [Err(InternalFailure("TonicLogsClient export failed with gRPC code: Unavailable: transport error: tcp connect error: tcp connect error: Connection refused (os error 111)"))]
Flush before the process exits, or the batch the SDK is holding goes with it.
Find your events in the collector¶
Each event arrives as a log record with event name
rtb.telemetry.event, a severity of INFO or ERROR, the redacted event
as a JSON string body, and attributes tool, tool.version and
event.name.
The resource's service.name is the constant "rtb-telemetry" unless you
set it in resource_attrs, so query by the tool attribute — or set
service.name yourself, as in the first example, if your backend's
navigation is built around services.
Do not expect traces or metrics¶
OtlpSink emits log records only. This crate is product analytics about a
user's tool, not instrumentation of a running service; if you want spans
and metrics, wire the OpenTelemetry SDK up directly alongside it.