-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Reusable handle to thread-local replaceable stdout/err #50457
Conversation
Lays the groundwork for mitigating: - rust-lang#12309 - rust-lang#31983 - rust-lang#40298 - rust-lang#42474
r? @kennytm (rust_highfive has picked a reviewer for you, use r? to override) |
As an example usage, I currently have the following helper function for tests in a workspace using fn make_logger() -> ::slog::Logger {
use slog::{Drain, Logger};
use std::{io, sync::Mutex};
Logger::root(
Mutex::new(
slog_term::CompactFormat::new(
slog_term::PlainSyncDecorator::new(io::stdout())
).build().fuse()
).fuse(),
o!(),
)
} With the approach taken in this PR, I should be able to replace The alternate solution here would be to create a new logger type that uses |
Thanks for the PR! This I think is pretty highly related to the work being done on custom test frameworks and so I'm somewhat hesitatnt to land without weighing in with those folks. In terms of this particular solution I've never been too fond of the ability to override stdout/stderr in libstd and it was basically always just a necessary evil of thet test harness itself. I'd prefer to pursue different avenues to avoid libtest needing to capture entirely first before we add more api surface area to libstd itself. |
Seems reasonable to me! (I'm fine with closing this PR for the time being to reduce clutter if that's desired.) The stdout/stderr overriding is only necessary as I understand it because stdout/stderr are by-process and the test harness works by spawning threads in-process to run the individual tests. If you point me in the direction where the test harness discussion is happening, I'd be happy to participate, I'm just not exactly certain where that is, though I've been excited by what bits of it I've stumbled across. |
I'm not sure myself exactly where the test framework discussion is happening, but I suspect that @killercup might! |
Ping from triage @alexcrichton! If I understood correctly this is blocked on the discussion about custom test frameworks? |
Ok I'm gonna close this in favor of that issue, @CAD97 mind writing up your thoughts though on the issue about the problem here with this possible solution? |
It has been done. See #50297 (comment) for my current thoughts. TL;DR: To have sane capture behavior for stdout and stderr for print-family macros, panic, and io::{stdout, stderr}, running each test in its own (child) process is probably required. I'd love to help out wherever I can, but lack confidence. |
@CAD97 ok, thanks for the comment! |
Lays the groundwork for mitigating:
cargo test
doesn't capture print from threads #42474When running tests with logging, logs directed to
io::stdout()
are not captured by the test runner, and intermingle with the test runner's output. This does not aim to directly solve that problem, but rather provides the infrastructure towards allowing users to opt-in to the same behavior thatprintln!
and friends have in regards to std(out|err) for any type generic overWrite
.By providing
LocalStderr
/LocalStdout
, when building logging for tests, the logger can be constructed to useio::LocalStdout
rather thanio::stdout()
, which will redirect the output with the exact same mechanism thatprintln!
output is captured in the test runner.The hidden fn
_print
and_eprint
have not been removed to avoid necessitating inlining the panicking code for if stdio/stdout error. However, they have been adjusted to write toLocalStdout
/LocalStderr
.print_to
has been replaced withwith_write
, allowing theWrite
impls to defer to the backingWrite
implementation for all methods.Is this approach amenable? Is this approach towards allowing well-behaved logs to be captured by test runners one that could in the future potentially be stabilized? Would that require a full RFC? (I can write one up.) (I'm not exactly certain how to add a new feature gate, so for now they're gated by
set_stdio
, which isn't wrong.) Any bikeshed on naming?This is mostly a proof-of-concept that this approach would (hopefully) work. Alternately, this switching behavior can be added directly onto
io::Stdin
/Stdout
, in which case the local versions would not be needed, and test output capturing would be closer to avoiding leakage, but spawning a new thread would still avoid the capture, as the approach used to change stdout in tests is inherently thread-local.(My local
./x.py test
also stalled out due to what I assume is an environment error, so I'm hoping Travis will indicate if I messed something up horribly.)WARNING: this touches the output routine used by
print!
/eprint!
/the default panic handler.HANDLE WITH CAUTION