Skip to main content
Logfire for Rust

Rust observability with OpenTelemetry

OpenTelemetry-native observability for any Rust app, from the team behind Pydantic. Built on the tracing crate, so the instrumentation you already have keeps working, and query all of it with SQL. Free for 10 million spans, logs, and metrics a month.

Start free with Rust As Markdown
Getting started

A few lines to your first trace

cargo add logfire
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. The region is taken from the token, so there is no endpoint to configure. Records are buffered and flushed on shutdown, so keep the guard alive for the life of the process. Full details are in the Rust setup guide.

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

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
Migration

Your existing tracing code already works

#[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.

Traces, metrics, and logs in one place

Logfire is not just tracing. Send metrics and structured logs alongside your traces, build dashboards, and set alerts, all in the same OpenTelemetry-native project, and query all of it with the same SQL.

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 telemetry with 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;

Your traces, metrics, and logs are queryable with real SQL, no proprietary query language to learn. Any question you can express becomes a dashboard, an alert, or a one-off investigation.

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
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.