Integration · Rust

Rust monitoring with OpenTelemetry

Bridge the tracing crate to OpenTelemetry and Obseria shows spans, metrics and logs from your Rust services over OTLP, correlated with CPU profiles, infrastructure and every upstream caller.
Obseria apps and capabilities: observability, APM, infrastructure and integrations
Obseria home dashboard with service health, open problems, SLO compliance and ingestion
Obseria trace explorer with span list and span attributes
Overview

Why monitor Rust with Obseria

Keep the tracing crate

tracing-opentelemetry turns the spans and #[instrument] attributes you already use into OpenTelemetry traces, without rewriting instrumentation.

Standard OTLP export

The opentelemetry-otlp crate sends traces, metrics and logs to Obseria over HTTP or gRPC, with no vendor-specific crate.

Profiles for hot paths

Continuous profiling with under 1% overhead shows which functions consume CPU in production, next to the traces they slow down.

Coverage

Rust crates and runtimes Obseria monitors

  • tracing and tracing-opentelemetry. Spans from #[instrument] and tracing macros are exported as OpenTelemetry spans with fields as attributes.
  • Tokio-based services. Async tasks keep their span context across .await points, so concurrent work appears in the right trace.
  • Axum, Actix Web and Tower middleware. HTTP servers get one span per request through tracing-aware middleware, with route and status code.
  • Reqwest, Tonic and other clients. Outbound HTTP and gRPC calls can inject W3C trace context to connect Rust with services in other languages.
  • SQLx, Diesel and Redis clients. Database and cache calls wrapped in spans show query duration and errors.
  • Logs via opentelemetry-appender-tracing. tracing events are exported as OpenTelemetry logs and linked to the active trace.
At a glance

The Rust signals that matter

Obseria collects these values automatically and shows them in ready-made dashboards and alerts.

Response speed and demand

Shows how quickly your Rust services answer and how many requests they are handling at the same time.

  • http.server.request.duration
  • http.server.active_requests

Dependency speed

Tells you how long your application waits for databases and other services, revealing slow external dependencies.

  • http.client.request.duration
  • db.client.operation.duration

Computing resources

Reveals how much processing power and memory the application uses, helping you size servers and control costs.

  • process.cpu.utilization
  • process.memory.usage

Internal housekeeping

Shows how many threads and open connections the application keeps, so slow leaks are noticed before they cause outages.

  • process.threads
  • process.open_file_descriptors
Show all 8 metrics in detail
MetricUnitWhat it tells you
http.server.request.durationsLatency histogram of inbound HTTP requests per route and status code.
http.server.active_requests{request}Requests in flight; growth with flat throughput means tasks are stuck.
http.client.request.durationsLatency of outbound HTTP calls to downstream services.
db.client.operation.durationsDuration of database operations, to find slow queries.
process.cpu.utilization1CPU share used by the Rust process, collected by the Collector hostmetrics receiver.
process.memory.usageByResident memory of the process; steady growth points to a leak or unbounded cache.
process.threads{thread}OS threads of the process, including Tokio worker and blocking threads.
process.open_file_descriptors{count}Open file descriptors; climbing values reveal leaked sockets or files.
Setup

Set up Rust monitoring in minutes

  1. Step 1

    Add the crates

    Add opentelemetry, opentelemetry_sdk, opentelemetry-otlp and tracing-opentelemetry in matching versions to Cargo.toml.

  2. Step 2

    Install the layer

    Build an SdkTracerProvider with the OTLP exporter and register tracing_opentelemetry::layer() in your tracing subscriber.

  3. Step 3

    Point it to Obseria

    Set OTEL_SERVICE_NAME, the Obseria OTLP endpoint and your token; the Obseria Agent adds process and host metrics.

Example configuration · RUST
// Cargo.toml: opentelemetry = "0.33", opentelemetry_sdk = "0.33",
//   opentelemetry-otlp = { version = "0.33", features = ["http-proto", "reqwest-blocking-client"] },
//   tracing = "0.1", tracing-subscriber = "0.3", tracing-opentelemetry = "0.34"
use opentelemetry::trace::TracerProvider as _;
use opentelemetry_otlp::SpanExporter;
use opentelemetry_sdk::{trace::SdkTracerProvider, Resource};
use tracing_subscriber::prelude::*;

// OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS
// (Authorization=Bearer%20${OBSERIA_TOKEN}) are read from the environment.
fn init_tracing() -> SdkTracerProvider {
    let exporter = SpanExporter::builder()
        .with_http()
        .build()
        .expect("failed to create OTLP exporter");
    let provider = SdkTracerProvider::builder()
        .with_batch_exporter(exporter)
        .with_resource(Resource::builder().build())
        .build();
    tracing_subscriber::registry()
        .with(tracing_opentelemetry::layer().with_tracer(provider.tracer("orders-api")))
        .with(tracing_subscriber::fmt::layer())
        .init();
    provider // call provider.shutdown() before exit to flush spans
}

Out of the box

Dashboards, alerts and SLOs that are ready the moment data arrives.

  • Rust service health with RED metrics per route
  • Process view: CPU, memory, threads, file descriptors
  • Alert on p99 latency per endpoint
  • Alert on steadily rising process memory
  • Slowest database and downstream calls
Guide

Rust monitoring: what matters

Why Rust monitoring matters

Teams choose Rust for performance-critical services: proxies, data pipelines, trading and payment engines, and backends where memory safety and predictable latency matter. The compiler removes whole classes of bugs, but it does not tell you how a service behaves under production load. Async tasks can block the Tokio runtime, a downstream service can slow down, and caches can grow without bound. Rust monitoring gives you traces, metrics and logs to see where time and resources go.

The Rust ecosystem has a strong convention for instrumentation: the tracing crate. Many libraries already emit spans and events through it. The tracing-opentelemetry layer converts them into OpenTelemetry spans, and opentelemetry-otlp exports them to any OTLP backend. According to the OpenTelemetry project, Rust metrics and logs are stable, while traces are still classified as beta, so expect occasional API changes between minor releases and pin matching crate versions.

Signals that matter for Rust performance monitoring

  • Request latency and errors: http.server.request.duration per route and error spans give the RED view per service. Record it with metrics middleware or your own instruments that follow the semantic conventions.
  • Concurrency: http.server.active_requests rising while throughput stays flat signals tasks waiting on locks, pools or slow dependencies.
  • Dependencies: http.client.request.duration and db.client.operation.duration show how much latency comes from other systems.
  • Process resources: process.cpu.utilization, process.memory.usage, process.threads and process.open_file_descriptors come from the Collector hostmetrics receiver or the Obseria Agent, without any code.

Rust has no runtime agent and no bytecode injection. Coverage therefore depends on which crates emit tracing spans and where you add #[instrument]. Start at the edges, inbound requests and outbound calls, and add spans inside the service where latency is unclear.

Common Rust performance problems and how to detect them

Blocking the async runtime

Synchronous I/O or heavy computation inside an async task stalls a Tokio worker thread and delays every other task on it. Traces show unexplained gaps between spans, and CPU profiles point to the blocking function. Move such work to spawn_blocking or a dedicated pool.

Unbounded memory growth

Caches without eviction, growing channels or leaked tasks raise resident memory over time. A trend alert on process memory catches the issue before the container is killed.

Lock contention

A shared mutex on a hot path serializes requests. Active requests rise, latency grows and CPU stays moderate. Spans around critical sections make the waiting time visible.

Slow dependencies

Missing timeouts on HTTP or database clients let slow downstream calls pile up. Client spans with high latency identify the dependency immediately.

Too much span data

Instrumenting every small function produces large traces and high ingest volume without more insight. Watch span counts per trace and keep detailed spans at debug level, enabled only where you investigate.

Best practices for Rust observability

  1. Pin opentelemetry, opentelemetry_sdk, opentelemetry-otlp and tracing-opentelemetry to versions that are released together.
  2. Use #[instrument(skip(...))] to avoid recording large or sensitive arguments, and mask remaining PII in Obseria Pipeline.
  3. Set service.name, service.version and deployment.environment.name through environment variables.
  4. Call shutdown() on the providers before exit so batched spans are flushed.
  5. Propagate W3C trace context on every outbound call to connect Rust with services in other languages.

How Obseria helps with Rust monitoring

Obseria accepts traces, metrics and logs from the OpenTelemetry Rust SDK over OTLP, so you use standard crates only. The Obseria Agent adds process, host and Kubernetes metrics and continuous profiling with under 1% overhead. TopoGraph places each Rust service in the dependency map next to services written in Java, Go or Python. When latency rises, Obseria Intelligence correlates slow spans, resource trends and deployments and presents the root cause with its chain of evidence. Dashboards, alerts and SLOs are included.

Rust monitoring FAQ

Many teams run it in production. The OpenTelemetry project lists Rust metrics and logs as stable and traces as beta, so APIs can still change between minor versions. Pin matching crate versions and review release notes when you upgrade.

No. tracing-opentelemetry is a layer for tracing-subscriber. Your existing spans and #[instrument] attributes are exported as OpenTelemetry spans, and console logging can stay as it is.

Rust has no runtime agent like Java or Python. Instrumentation comes from crates that emit tracing spans and a few lines of setup. Process and host metrics are collected by the Obseria Agent without code changes.

Use opentelemetry-appender-tracing to send tracing events as OpenTelemetry logs over OTLP. They carry the trace and span IDs of the active span, so logs and traces are linked in Obseria.

Yes. Deploy the Obseria Agent as a DaemonSet via Helm and set the OTEL_* variables in your pod spec. Traces are enriched with pod, namespace and node metadata.

Start monitoring Rust today

Connect Rust in minutes with OpenTelemetry or the Obseria Agent. Free for 14 days.