Logging and Tracing

warp provides filters for logging requests and integrating with the tracing ecosystem for rich, structured diagnostics.

Simple Access Logging (warp::log)

For basic access logging, warp provides the warp::log() filter. It wraps another filter and logs a summary of each request and its response to the standard log facade.

use warp::Filter;

// To view logs, you might need to initialize a logger, like `pretty_env_logger`.
// Run with `RUST_LOG=my_app=info` to see the logs.
// pretty_env_logger::init();

let log = warp::log("my_app");

let routes = warp::any()
    .map(|| "Hello, World!")
    .with(log);

A typical log line looks like this:

INFO  my_app > "GET / HTTP/1.1" 200 "-" "curl/7.64.1" 2.13µs

This format includes the request method, path, HTTP version, response status code, referer, user-agent, and latency.

Advanced Diagnostics with warp::trace

For more advanced and structured diagnostics, warp integrates with the tracing crate. This allows you to create spans for requests, which group together all related events and logs, providing a clear context for what happened during a request's lifecycle.

Setting up tracing

First, you need to set up a tracing subscriber. tracing-subscriber is a common choice.

use tracing_subscriber::fmt::format::FmtSpan;

// In your main function:
tracing_subscriber::fmt()
    .with_env_filter("info,warp=debug")
    // Log events when spans close, which includes latency.
    .with_span_events(FmtSpan::CLOSE)
    .init();

Using the Trace Filters

  • warp::trace::request(): This is the main filter to wrap your entire API. It creates a tracing::info_span! for each incoming request, automatically including fields like method, path, and remote address.

    use warp::Filter;
    let routes = some_filter
        // ...
        .with(warp::trace::request());
    
  • warp::trace::named("..."): This filter creates a sub-span within the main request span. It's useful for instrumenting specific parts of your application to see how much time is spent in different sections.

    use warp::Filter;
    let users_api = warp::path("users")
        .map(|| "users")
        .with(warp::trace::named("api::users"));
    let products_api = warp::path("products")
        .map(|| "products")
        .with(warp::trace::named("api::products"));
    let routes = users_api.or(products_api)
        .with(warp::trace::request());
    
  • warp::trace::trace(|info| ...): For full control, this filter allows you to construct your own Span using the Info struct, which contains details about the request.

By using warp::trace, you can produce detailed, structured logs that are invaluable for debugging and monitoring your application.