Use tracing-subscriber to log only Debug to file

I have a Debug log, but it seems to also get Info, Error, and Debug, when I want it to only have Debug. I'm having a difficult time understanding a lot of tracing-related terminology, so forgive me if this is a simple fix.

use ex_06_bookstore_app::app;
use std::fs::OpenOptions;
use tracing::{info, error, Level, debug};
use tracing_subscriber::{
    prelude::*,
    fmt,
    layer::Layer,
    Registry, filter
};

#[tokio::main]
async fn main() {
    let err_file = OpenOptions::new()
        .append(true)
        .create(true)
        .open("log-error.log")
        .unwrap();
    let debug_file = OpenOptions::new()
        .append(true)
        .create(true)
        .open("log-debug.log")
        .unwrap();

    let subscriber = Registry::default()
        .with(
            // stdout layer, to view everything in the console
            fmt::layer()
                .compact()
                .with_ansi(true)
        )
        .with(
            // log-error file, to log the errors that arise
            fmt::layer()
                .json()
                .with_writer(err_file)
                .with_filter(filter::LevelFilter::from_level(Level::ERROR))
        )
        .with(
            // log-debug file, to log the debug
            fmt::layer()
                .json()
                .with_writer(debug_file)
                .with_filter(filter::LevelFilter::from_level(Level::DEBUG))
        );
    
    tracing::subscriber::set_global_default(subscriber).unwrap();
    
    // Opens the server
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await.unwrap();
    println!("Server is running on localhost:3000");
// ------ The issue ------
    // All three go into log-debug.log
    error!("test"); // Only thing log-error.log gets
    info!("test2");
    debug!("test3");
    // app is a standard Axum Router that I have inside `lib.rs`
    axum::serve(listener, app().await).await.unwrap();
}

the provided LevelFilter will record all events and spans with verbosity greater or equal to the filter level. if you want a filter that matches exact level, you'll have to define your own Filter.

struct DebugOnlyFilter;
impl Filter for DebugOnlyFilter {
    fn enabled(&self, meta: &Metadata<'_>, _: &Context<'_, S>) -> bool {
        meta.level() == &Level::DEBUG
    }
}
1 Like