Idea: Allow capturing log output from multiple threads in a test


#1

Here’s my predicament: I have a large rust application with a bunch of tests, and many (if not most) of those tests spin up and then shut down one or more worker threads. Most of the interesting application logic happens on these other threads - so most interesting println! statements that I might want to add don’t get captured in the current libtest test framework. Instead, all the output ends up going to stdout/stderr, regardless of whether the corresponding test succeeds or fails.

(Sidebar: Technically, I’m currently using slog and a lightly customized config that dumps to stderr - but I can easily redirect those messages to println! to better conform to the existing libtest behavior of capturing println!s but not stderr)

What I’d like to do, is provide some way of specifying or overriding the behavior to allow redirecting output of these worker threads into the buffer that libtest keeps for each test case.

I’ve dug a little bit into how println! and libtest’s output capture interact via the undocumented std::io::stdio::set_print function - and as far as I can tell, I don’t think this is possible, since I can’t get a handle on the LOCAL_STDOUT for the current thread (the one that libstd overrode using set_print).

For the moment, I’d like to propose making solving this usecase possible, and maybe later look at what it takes to make this behavior clean/extensible/suitable for stabilization.

I think the bare minimum change to the standard library that would allow me to implement this myself is introducing a get_print function, that just reads and returns LOCAL_STDOUT (and corresponding get_panic, because why not). Then, before I spawn these threads in my application, I can call get_print to grab whatever the current one is, and the call set_print in the “child” thread before doing any meaningful work.

Thoughts?


#2

There’s a Rust issue about this:

This just came up on Rayon too:


#3

Oh nice, thanks for the pointers! It looks like someone in the rayon conversation came to pretty much exactly the same conclusion with stdio::get_stdio (which I think is what I was calling get_print).

This would be a super simple change to make - is it worth just opening a pr on rust-lang/rust? What’s the right way to move this forward?


#4

Ah, except now that I think about it - it’s not quite that simple. The LOCAL_STDOUT is a Option<Box<dyn Write + Send>>, which isn’t clonable like we would need. :thinking:


#5

(Links are to two different comments)

Status: it’s very possible to use custom test frameworks to do proper stdout/stderr capture naively. It’s harder to do it efficiently.