DEV Community

Hermosilla
Hermosilla

Posted on

Rust Observability in 2026: OTLP Logs and Metrics Are Stable—What About Traces?

Rust has a strong observability ecosystem built around tracing, but getting its events into an observability backend involves a few distinct pieces: spans, log records, metrics, and exporters.

There is a useful milestone in the current OpenTelemetry Rust release that makes this setup more interesting: as of OpenTelemetry Rust 0.33.1, the OTLP exporters for logs and metrics are stable, while the OTLP exporter for traces remains in beta.

That distinction is easy to miss if we just say “OpenTelemetry is stable.” Let’s look at what changed and how it maps to a real Rust service.

What became stable?

The OpenTelemetry Rust 0.33.1 release, published on October 8, 2026, declared the OTLP exporters for Logs and Metrics stable after a release-candidate period. The Traces exporter remains beta.

Signal OTLP exporter status in 0.33.1
Logs Stable
Metrics Stable
Traces Beta

This is specifically about the OTLP exporters in the Rust implementation—not a blanket statement that every OpenTelemetry crate or API has the same stability guarantee. The release notes also describe the Logs and Metrics APIs and SDK as stable, while Distributed Tracing remains pre-stable.

There is another useful reliability improvement: starting in 0.33.0, OTLP retries are enabled by default for HTTP and gRPC exporters. The default policy uses exponential backoff and jitter, with up to three retries after the first attempt. In other words, a temporary collector hiccup no longer necessarily means an export is immediately lost.

tracing events can become either logs or trace data

One source of confusion is that two similarly named integrations do different jobs:

Both can be installed as layers on a tracing_subscriber. A log record and a span event are related, but they are not the same telemetry signal; the bridge you choose determines where the event goes.

In our service setup, the key pieces look like this:

let trace_layer = tracing_opentelemetry::layer().with_tracer(tracer);
let log_layer = OpenTelemetryTracingBridge::new(&logger_provider);
Enter fullscreen mode Exit fullscreen mode

The trace provider and logger provider each receive exporters. The metrics provider is separate again: it creates instruments and collects measurements on its configured interval. All three can share the same OpenTelemetry Resource, so telemetry is attributed to the same service name and version.

A small configuration example

The AICC crate wraps provider and subscriber setup behind a builder-style API. With a local OpenTelemetry Collector listening on gRPC port 4317, initialization is just a few lines:

use aicc::o11y::prelude::*;
use tracing::info;

let options = TracingOptions::default()
    .with_service("orders-api", "1.2.0")
    .with_otlp_exporter(OtlpExporterOptions::new("http://localhost:4317"));

let _guard = init_tracing(&options)?;

info!(order_id = 42, "Order accepted");
Enter fullscreen mode Exit fullscreen mode

The exporter options enable all three signals by default. In the implementation, separate builders create the OTLP span, metric, and log exporters, and the resulting providers are attached to the subscriber or registered as global providers where needed.

The returned guard matters. Keep it alive for the lifetime of the application: when it is dropped, it shuts down the providers and flushes pending telemetry. If you create a provider manually, make sure your shutdown path does the equivalent.

A practical detail: exporters can produce telemetry too

The OTLP exporter and its transport stack can emit tracing events of their own. If those events are sent through the log bridge, exporting a log could produce another log, which could trigger another export, and so on.

The service code avoids that feedback loop by filtering infrastructure targets out of the OpenTelemetry log layer. It still allows warnings and errors from that infrastructure to appear in the console layer, which is useful when the collector is unavailable.

This is a small implementation detail, but it is exactly the sort of thing that turns a “hello, telemetry” demo into a setup you can operate.

Metrics are collected when requested

OpenTelemetry observable instruments use callbacks that run during collection. They are a good fit for values such as current CPU or memory usage: the application registers how to read the value, and the SDK asks for it when a metrics reader collects data.

In this project, the server registers observable system metrics using sysinfo. The callbacks refresh and read the relevant values; there is no separate polling task that wakes up just to update gauges. If you adapt the example for your own service, you can add application counters or histograms alongside those system metrics.

One caveat for a demo: the OTLP example initializes all three pipelines and emits spans and log records, but it does not record a custom metric. To demonstrate all three signals end to end, add a metric instrument or run the server path that registers the system metrics.

What should you take away?

OpenTelemetry Rust 0.33.1 is a meaningful point to revisit your observability setup:

  1. Logs and metrics have stable OTLP exporters. That is useful if you want to standardize your output format and backend integration.
  2. Tracing is still beta. Treat its API stability separately rather than assuming every signal has the same guarantee.
  3. Retries are now on by default for OTLP exporters. That improves resilience to transient failures, but it is still worth monitoring exporter errors and having a clear shutdown path.
  4. tracing can feed more than one signal. Use the trace bridge for spans and the appender for OpenTelemetry log records, and filter exporter-generated events to prevent feedback loops.

The interesting question is no longer just “Can Rust send telemetry to OpenTelemetry?” It can. The more useful question is: which signals are stable in the versions you deploy, and what does your application do when the collector is slow or unavailable?

References

Top comments (0)