---
title: Rust Observability with OpenTelemetry | Pydantic Logfire
description: >-
  Instrument any Rust app with OpenTelemetry and Pydantic Logfire. Your existing
  tracing macros work unchanged, and you query traces, metrics, and logs with
  SQL.
canonical: 'https://pydantic.dev/logfire/rust'
---

> Markdown version of [Trace, monitor and debug your Rust app](https://pydantic.dev/logfire/rust) — the canonical HTML page.
>
> Site index: [/llms.txt](https://pydantic.dev/llms.txt)

---

# Trace, monitor and debug your Rust app

Logfire for Rust

Rust Observability from the team behind Pydantic: build on tracing, keep your existing spans and events, and query everything in plain SQL. Standard OpenTelemetry, no lock-in.

[Try Logfire for free](https://logfire.pydantic.dev/login?intent=signup) [See the Rust docs](https://pydantic.dev/docs/logfire/instrument/rust/)

Set up Logfire with your coding agent:

uvx logfire-cli wizard

Install and configure

```bash
cargo add logfire
```

Instrument your app

View code

```rust
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads LOGFIRE_TOKEN from the environment. The region is taken from the token.
    let logfire = logfire::configure()
        .send_to_logfire(logfire::config::SendToLogfire::IfTokenPresent)
        .with_service_name("hello-rust")
        .finish()?;

    // The guard flushes and shuts Logfire down when it goes out of scope.
    let _guard = logfire.shutdown_guard();

    logfire::span!("hello").in_scope(|| {
        logfire::info!("Hello world");
    });

    Ok(())
}
```

Set LOGFIRE\_TOKEN and run. Full details are in the [Rust setup guide](https://pydantic.dev/docs/logfire/instrument/rust/).

Trusted by teams building production software and AI

**Customers:** Motorola, Sophos, Airbyte, Pictet, Vox Media, Weaviate, Amboss, Tiger Data

What you get

## One request, one trace

![A Logfire trace of a Rust request: the axum handler and its instrumented functions, with a failed lookup recorded as an error below](https://pydantic.dev/assets/logfire/language-traces/rust-trace.png)

**What lands in Logfire:**

* your `#[tracing::instrument]` functions, with their arguments attached
* every `tracing` event your code and dependencies emit
* nesting that follows the call tree, including across `await`
* a failed lookup, marked red at the span that failed

Try it on your stack

## See your own Rust trace

Start free with 10 million spans, logs, and metrics each month. No credit card required.

[Start free](https://logfire.pydantic.dev/login?intent=signup) [Read the Rust setup guide](https://pydantic.dev/docs/logfire/instrument/rust/)

Migration

## Your existing tracing code already works

```rust
#[tracing::instrument]
fn my_function(param: &str) {
    // the attribute creates a span, with param as an attribute on it
    tracing::info!("This also appears in Logfire");
}
```

This is not a migration. The `logfire` crate builds on `tracing` and OpenTelemetry, so libraries and code you have already instrumented send through Logfire unchanged. The `log` crate is captured and forwarded too.

How it works

## Instrument what matters

### Your existing tracing code already works

The logfire crate is built on the tracing crate and OpenTelemetry, so adopting it is not a migration. Any code or dependency already using tracing macros sends through Logfire unchanged: tracing::info! events appear, and #\[tracing::instrument] creates a span with the function's parameters as queryable attributes. The log crate is captured and forwarded too, so dependencies that log show up without extra configuration.

### Structured spans, not string logs

Record a unit of work with logfire::span!("process order {order\_id}", order\_id = order\_id).in\_scope(...). The span carries a name, a duration, and the attributes you attach, so "every order that took longer than two seconds" becomes a real query rather than a grep through log lines.

### Async is first class

Rust observability lives or dies on async context propagation. Create a span, then attach it to a future with .instrument(span) from tracing::Instrument. Context follows the task across await points, so nested work is attributed to the correct parent span instead of whichever task happened to be polling.

### Works with the crates you already run

Because the SDK builds on tracing, anything in your dependency tree that emits tracing spans arrives in Logfire with no vendor integration in between, and the log crate is forwarded too. Producing those spans is still the ecosystem's job rather than ours: add tower\_http::trace::TraceLayer for an axum or tower service, reqwest-tracing for outbound HTTP, and Logfire records whatever they emit. The thing you are never waiting on is a vendor shipping support for your framework.

### Building agents in Rust? Rig works out of the box

Rig agent, model, and tool telemetry flows through the Logfire Rust SDK, so agent runs, the models they call, and the tools they invoke all show up alongside the rest of your service. Rust is not a second-class citizen for AI work here.

### Your Rust signals stay connected

Logfire puts tracing spans and events, forwarded log records, and OpenTelemetry metrics in one project. Query them with the same SQL, then save the useful questions as dashboards or alerts.

### OpenTelemetry-native, no lock-in

Because Logfire speaks OpenTelemetry natively, you are never trapped. Prefer the raw OpenTelemetry Rust SDK? It works instead of the logfire crate. You can export the same data to another backend or self-host without touching your instrumentation. Your instrumentation is an asset you own, not rented from a vendor.

Query

## Query your Rust telemetry with SQL

If you can ask it, SQL can find out

* Query your traces, metrics and logs with real SQL
* No proprietary query language to learn
* AI models are great at writing SQL
* From a one-off investigation to an alert, dashboard, or SLO

```sql
select
  span_name,
  count(*) as spans,
  avg(duration) as avg_seconds
from records
where duration > 1
group by span_name
order by avg_seconds desc;
```

Proof

## In production

> You can tell that Pydantic Logfire was built by people who use it.

Dennis Griffin, VP of Engineering, Sophos [Read the case study](https://pydantic.dev/case-studies/sophos)

Decision guide

## Is Logfire right for you?

### Choose Logfire if

* You already use the tracing crate and want a backend without re-instrumenting
* You want spans that survive async await points with correct parent context
* You want to query traces, metrics, and logs with PostgreSQL-compatible SQL
* You want observability for a Rust service without running a backend yourself
* You want the portability of OpenTelemetry rather than a proprietary agent

### Choose a traditional APM if

* You are already deeply integrated with a specific APM vendor's ecosystem
* You need a vendor-only integration or compliance capability Logfire does not offer
* You want one vendor's agent and dashboards, and are comfortable with their pricing model

FAQ

## Common questions

### How do I add OpenTelemetry to a Rust application?

Run cargo add logfire, then call logfire::configure() with your service name and finish it, and hold the returned shutdown guard for the life of the process. The logfire crate is built on OpenTelemetry and the tracing crate, so spans from your own code and from dependencies are exported automatically. If you prefer raw OpenTelemetry, the standard OTel Rust SDK works instead.

### Does Logfire replace the tracing crate?

No. Logfire builds on tracing rather than replacing it. Your existing #\[tracing::instrument] attributes and tracing macros keep working exactly as they do today; Logfire gives them a backend, a UI, and SQL querying. Libraries that use the log crate are captured and forwarded too, with no extra configuration.

### Why is nothing showing up in Logfire?

Two common causes. With SendToLogfire::IfTokenPresent, a missing LOGFIRE\_TOKEN disables sending silently, so check the environment variable is set. Second, records are buffered and flushed on shutdown, so the binding returned by shutdown\_guard() must stay alive for the whole run. Add with\_console to print records to your terminal while debugging.

### How do spans work with async Rust?

Use Instrument from the tracing crate to attach a span to a future: create the span with logfire::span!, then call .instrument(span) on the async block. Context then follows the task correctly across await points, so nested work is attributed to the right parent span rather than whichever task happened to be running.

### Is Pydantic Logfire locked to a proprietary format?

No. Logfire is built on OpenTelemetry, the open industry standard. Your instrumentation is portable: you can export the same data to another OTel-compatible backend, and standard OpenTelemetry tooling works. Logfire adds ergonomics and SQL querying on top of the open standard.

## Start seeing your Rust service

Get started with 10 million free spans, logs, and metrics per month. No credit card required.

* [Start free](https://logfire.pydantic.dev/login?intent=signup)
* [Book a demo](https://pydantic.dev/contact)
* [View pricing plans](https://pydantic.dev/pricing)
