Tracing - multiple RollingFileAppenders

I'm setting up tracing like this:

fn init_tracing() -> WorkerGuard {
    let appender = RollingFileAppender::builder()
        .rotation(Rotation::DAILY)
        .filename_prefix("server.log")
        .build("./log")
        .expect("failed to initialize tracing");

    let (non_blocking, guard) = tracing_appender::non_blocking(appender);
    tracing_subscriber::fmt()
        .with_file(true)
        .with_thread_ids(true)
        .with_target(false)
        .with_writer(non_blocking)
        .init();

    guard
}

I'd love to be able to have two RollingFileAppenders, one at Info level and one at Trace (if you've done production support you know why). Surprisingly there seems to be no obvious way to do this.

I'd settle for one RollingFileAppender and another just to stdout (which I'd redirect).

You can create a Layer for each RollingFileAppender, then use SubscriberExt::with on a Subscriber[1].

I think the Subscriber you want here is not tracing_subscriber::fmt::Subscriber, but actually tracing_subscriber::Registry. Filtering methods like with_target are available on the Layer type, which is different from the Layer trait. You can also configure the writer per-Layer.
It could definitely be simpler to just use an FmtSubscriber, the key idea of this answer is using Layers to add multiple loggers.


  1. the trait, not the struct ↩︎