Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fmt::Subscriber's output is not captured by cargo test #2404

Closed
e00E opened this issue Dec 2, 2022 · 0 comments
Closed

fmt::Subscriber's output is not captured by cargo test #2404

e00E opened this issue Dec 2, 2022 · 0 comments

Comments

@e00E
Copy link

e00E commented Dec 2, 2022

cargo test captures test Stdout and Stderr output so that it can print only the output of failing tests after all tests have been run. This also prevents tests run in parallel from mixing their output.

fmt::Subscriber can output to Stdout and Stderr but this output is not captured by cargo test. This is annoying because of all the reasons cargo test wants to capture the output.

fn fn_print_and_log() {
    println!("print1");
    tracing::info!("trace1");
    println!("print2");
    tracing::info!("trace2");
}

#[test]
fn test1() {
    tracing_subscriber::fmt::fmt().init();
    fn_print_and_log();
}
$cargo test test1
running 1 test
2022-12-02T13:13:28.521203Z  INFO a: trace
2022-12-02T13:13:28.521235Z  INFO a: trace
test test1 ... ok
$cargo test test1 -- --nocapture
running 1 test
print1
2022-12-02T13:13:55.715215Z  INFO a: trace
print2
2022-12-02T13:13:55.715242Z  INFO a: trace
test test1 ... ok

This happens because output written directly to std::io::stdout() is not captured which is how fmt::Subscriber is implemented.

A stable but ugly solution I came up with is:

struct S;
impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for S {
    type Writer = W;

    fn make_writer(&'a self) -> Self::Writer {
        W
    }
}

struct W;
impl std::io::Write for W {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        // assume fmt::Subscriber only writes utf8 strings
        let string = std::str::from_utf8(buf).unwrap();
        print!("{}", string);
        Ok(buf.len())
    }

    fn flush(&mut self) -> std::io::Result<()> {
        // `print!` already flushes
        Ok(())
    }
}

#[test]
fn test2() {
    tracing_subscriber::fmt::fmt().with_writer(S).init();
    fn_print_and_log();
}

It is ugly because fmt::Subscriber only outputs strings which we convert to bytes for Write, convert back to strings to use print!, convert back to bytes in print!.

I would like this to be fixed in fmt::Subscriber but this this solution feels ugly enough that it shouldn't be used. If someone had an idea for a better solution I would be open to making a PR with it.

@tokio-rs tokio-rs locked and limited conversation to collaborators Dec 6, 2022
@davidbarsky davidbarsky converted this issue into discussion #2406 Dec 6, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant