Per-test file logging #1626
-
Hi, thanks for the great lib. I have 100+ tests, and I would like to set up a log file for each of them. However I want to have each test write to a separate file. Is it possible to:
Any tips appreciated! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 5 replies
-
I can think of a couple approaches that might be useful: Using the thread-local scoped dispatcherOne option, potentially the easiest, would just be to use the thread-local scoped trace dispatcher for each test, rather than initializing a global subscriber. You could write code like this: use std::{fs::File, error::Error};
use tracing::dispatch::DefaultGuard;
fn init_tracing(test_name: &str) -> Result<DefaultGuard, Box<dyn Error>> {
let file = File::create(format!("{}.log", test_name))?; // or however you want to name the log file
let subscriber = tracing_subscriber::fmt()
// ... however you would configure the subscriber goes here ...
.with_writer(Arc::new(file));
// Set the default subscriber for the _current thread_, returning a guard that unsets
// the default subscriber when it is dropped.
Ok(tracing::subscriber::set_default(subscriber))
}
#[test]
fn my_great_test() {
// the defautl subscriber will write to `my_great_test.log` for the duration of this test
let _guard = init_tracing("my_great_test").unwrap();
// ... the actual test ...
}
#[test]
fn my_other_cool_test() {
// the defautl subscriber will write to `my_other_cool_test.log` for the duration of this test
let _guard = init_tracing("my_other_cool_test").unwrap();
// ... the actual test ...
}
// ... and so on ... If this approach works for you, it might be the easiest way to get logs directed to a separate file for each test. You could also use With that said, there are some cases where this approach may not work and you will have to use the global default dispatcher. If your tests spawn their own threads, the default dispatcher context will not be propagated to the spawned threads unless you do so manually. For example, you will have to write: #[test]
fn my_test_that_spawns_threads() {
let _guard = init_tracing("my_test_that_spawns_threads").unwrap();
// ... test code ...
// spawn a new thread, propagating the dispatcher context
let dispatch = tracing::dispatcher::Dispatch::default();
std::thread::spawn(move || {
let _guard = tracing::dispatcher::set_default(dispatch);
// now the spawned thread is inside the same dispatcher context as
// the main test thread
// ... more code ...
});
} However, if threads are spawned in the code under test, or in external libraries, this approach may not work as well. If you're using Implementing
|
Beta Was this translation helpful? Give feedback.
I can think of a couple approaches that might be useful:
Using the thread-local scoped dispatcher
One option, potentially the easiest, would just be to use the thread-local scoped trace dispatcher for each test, rather than initializing a global subscriber. You could write code like this: