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.


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.
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.
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.
Dependency speed
Tells you how long your application waits for databases and other services, revealing slow external dependencies.
Computing resources
Reveals how much processing power and memory the application uses, helping you size servers and control costs.
Internal housekeeping
Shows how many threads and open connections the application keeps, so slow leaks are noticed before they cause outages.
Show all 8 metrics in detail
| Metric | Unit | What it tells you |
|---|---|---|
http.server.request.duration | s | Latency 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.duration | s | Latency of outbound HTTP calls to downstream services. |
db.client.operation.duration | s | Duration of database operations, to find slow queries. |
process.cpu.utilization | 1 | CPU share used by the Rust process, collected by the Collector hostmetrics receiver. |
process.memory.usage | By | Resident 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. |
Set up Rust monitoring in minutes
- Step 1
Add the crates
Add opentelemetry, opentelemetry_sdk, opentelemetry-otlp and tracing-opentelemetry in matching versions to Cargo.toml.
- Step 2
Install the layer
Build an SdkTracerProvider with the OTLP exporter and register tracing_opentelemetry::layer() in your tracing subscriber.
- 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.
// 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
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.durationper 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_requestsrising while throughput stays flat signals tasks waiting on locks, pools or slow dependencies. - Dependencies:
http.client.request.durationanddb.client.operation.durationshow how much latency comes from other systems. - Process resources:
process.cpu.utilization,process.memory.usage,process.threadsandprocess.open_file_descriptorscome 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
- Pin
opentelemetry,opentelemetry_sdk,opentelemetry-otlpandtracing-opentelemetryto versions that are released together. - Use
#[instrument(skip(...))]to avoid recording large or sensitive arguments, and mask remaining PII in Obseria Pipeline. - Set
service.name,service.versionanddeployment.environment.namethrough environment variables. - Call
shutdown()on the providers before exit so batched spans are flushed. - 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.
Related integrations
Related capabilities
Distributed Tracing
Follow each request across services, queues and databases with OpenTelemetry-native distributed tracing, and find the slow span or failing dependency in seconds.
Learn moreContinuous Profiling
Always-on continuous profiling shows which functions consume CPU, memory and locks in production, with under 1% overhead and direct links to traces.
Learn moreError Tracking
The Errors Inbox groups exceptions from backend, frontend and mobile apps into issues, shows their impact and lets teams assign and resolve them in one workflow.
Learn moreLearn more
What is OpenTelemetry?
What is OpenTelemetry? Learn how OTel's APIs, SDKs, Collector, OTLP and semantic conventions produce vendor-neutral traces, metrics, logs and profiles.
What is APM (application performance monitoring)?
What is APM? Learn how application performance monitoring measures latency, throughput and errors, how distributed tracing works, and which metrics matter.
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.