use std::env;
use std::io::Write;
use std::sync::{Arc, Mutex};
use tracing::subscriber::DefaultGuard;
use tracing::Level;
use tracing_subscriber::fmt::TestWriter;
#[derive(Debug)]
pub struct LogCaptureGuard(#[allow(dead_code)] DefaultGuard);
#[must_use] pub fn capture_test_logs() -> (LogCaptureGuard, Rx) {
let (mut writer, rx) = Tee::stdout();
if env::var("VERBOSE_TEST_LOGS").is_ok() {
eprintln!("Enabled verbose test logging.");
writer.loud();
} else {
eprintln!("To see full logs from this test set VERBOSE_TEST_LOGS=true");
}
let subscriber = tracing_subscriber::fmt()
.with_max_level(Level::TRACE)
.with_writer(Mutex::new(writer))
.finish();
let guard = tracing::subscriber::set_default(subscriber);
(LogCaptureGuard(guard), rx)
}
pub struct Rx(Arc<Mutex<Vec<u8>>>);
impl Rx {
pub fn contents(&self) -> String {
String::from_utf8(self.0.lock().unwrap().clone()).unwrap()
}
}
struct Tee<W> {
buf: Arc<Mutex<Vec<u8>>>,
quiet: bool,
inner: W,
}
impl Tee<TestWriter> {
fn stdout() -> (Self, Rx) {
let buf: Arc<Mutex<Vec<u8>>> = Default::default();
(
Tee {
buf: buf.clone(),
quiet: true,
inner: TestWriter::new(),
},
Rx(buf),
)
}
}
impl<W> Tee<W> {
fn loud(&mut self) {
self.quiet = false;
}
}
impl<W> Write for Tee<W>
where
W: Write,
{
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.buf.lock().unwrap().extend_from_slice(buf);
if !self.quiet {
self.inner.write_all(buf)?;
Ok(buf.len())
} else {
Ok(buf.len())
}
}
fn flush(&mut self) -> std::io::Result<()> {
self.inner.flush()
}
}