Tracing appender and subscriber traits: tracing_subscriber::fmt::writer::MakeWriterExt and std::io::Write

Hi,

I have two (2) questions regarding crates tracing-appender and tracing-subscriber, please.

The two (2) questions I have are about Trait tracing_subscriber::fmt::writer::MakeWriterExt and Trait std::io::Write.

For the example code, the questions related to both un-used code, used code and commented out code.

Content of Cargo.toml:
...
[dependencies]
tracing = "0.1.40"
tracing-appender = "0.2.2"
tracing-subscriber = {version = "0.3.17", features = ["fmt", "std", "local-time", "time"]}
Content of src/main.rs:
use tracing_subscriber::fmt::writer::MakeWriterExt;

struct TestWriter;

// This code is from https://docs.rs/tracing-appender/0.2.2/tracing_appender/
impl std::io::Write for TestWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        let buf_len = buf.len();
    
        println!("{:?}", buf);
        Ok(buf_len)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

// Non-Blocking Writer
// This code is also from https://docs.rs/tracing-appender/0.2.2/tracing_appender/
/*
fn main() {
    let (non_blocking, _guard) = tracing_appender::non_blocking(TestWriter);
    tracing_subscriber::fmt().with_writer(non_blocking).init();
}
*/

// Non-Blocking Rolling File Appender
fn main() {
    //
    // NOT MY CODE. I COPIED IT FROM ELSEWHERE, I am sorry, I did not write down the source URL :(
    //

    // Log all events to a rolling log file.
    let logfile = tracing_appender::rolling::hourly("./", "myapp-logs");
    // Log `INFO` and above to stdout.
    let stdout = std::io::stdout.with_max_level(tracing::Level::INFO);

    tracing_subscriber::fmt()
        // Combine the stdout and log file `MakeWriter`s into one
        // `MakeWriter` that writes to both
        .with_writer(stdout.and(logfile))
        .init();

    tracing::info!("I am testing...");
}

Question

If I removed use tracing_subscriber::fmt::writer::MakeWriterExt;, then:

let stdout = std::io::stdout.with_max_level(tracing::Level::INFO);

would have the following error:

37  |     let stdout = std::io::stdout.with_max_level(tracing::Level::INFO);
    |                                  ^^^^^^^^^^^^^^ method not found in `fn() -> Stdout {stdout}`

I understand that with_max_level is a method in trait tracing_subscriber::fmt::writer::MakeWriterExt; but how is it possible that function std::io::stdout "knows" when method with_max_level is "available", please?

I am not sure if I explain it correctly... I am thinking that instead of trait tracing_subscriber::fmt::writer::MakeWriterExt, if some other same type of trait also implements with_max_level, and we include this new trait instead, would function std::io::stdout chain this with_max_level method instead, please?

Question

Regarding TestWriter and its usage in the commented out main:

fn main() {
    let (non_blocking, _guard) = tracing_appender::non_blocking(TestWriter);
    tracing_subscriber::fmt().with_writer(non_blocking).init();
}

Is it possible to use TestWriter with a rolling log file, please? I'm thinking of something like this:

    let logfile = tracing_appender::rolling::hourly("./", "myapp-logs");

    tracing_subscriber::fmt()
        .with_writer(TestWriter ???? .and(logfile))
        .init();

I feel stupid asking these questions, but I just could not find anything searching...

Thank you and best regards,

...behai.

Reasoning:

  • there is a blanket impl for MakeWriterExt:
impl<'a, M> MakeWriterExt<'a> for M
where
    M: MakeWriter<'a>,
  • and for MakeWriter trait, it's implemented to a Fn() -> W where W implements std::io::Write trait like Stdout, so std::io::stdout() -> Stdout implements MakeWriter and thus MakeWriterExt with with_max_level available
impl<'a, F, W> MakeWriter<'a> for F
where
    F: Fn() -> W,
    W: Write, 

You can imitate TestWriter in tracing_subscriber::fmt - Rust which implements both Write and MakeWriter to write .with_writer(TestWriter.and(logfile))

1 Like

Hi vague,

Thank you very much for your very detail explanation. I would need to do more studies into your answer to the first question, I have seen those syntax in The Book, but they are still way over my head presently :slight_smile:

The links to the second answer are exactly what I am after.

Thank you kindly for your times and your helps.

Best regards,

...behai.