aws_smithy_runtime/test_util/
capture_test_logs.rs1use std::env;
7use std::io::Write;
8use std::sync::{Arc, Mutex};
9use tracing::subscriber::DefaultGuard;
10use tracing::Level;
11use tracing_subscriber::fmt::TestWriter;
12
13#[derive(Debug)]
15pub struct LogCaptureGuard(#[allow(dead_code)] DefaultGuard);
16
17#[must_use]
21pub fn show_test_logs() -> LogCaptureGuard {
22 let (mut writer, _rx) = Tee::stdout();
23 writer.loud();
24
25 let env_var = env::var("RUST_LOG").ok();
26 let env_filter = env_var.as_deref().unwrap_or("trace");
27 eprintln!(
28 "Enabled verbose test logging with env filter {env_filter:?}. \
29 You can change the env filter with the RUST_LOG environment variable."
30 );
31
32 let subscriber = tracing_subscriber::fmt()
33 .with_env_filter(env_filter)
34 .with_writer(Mutex::new(writer))
35 .finish();
36 let guard = tracing::subscriber::set_default(subscriber);
37 LogCaptureGuard(guard)
38}
39
40#[must_use] pub fn capture_test_logs() -> (LogCaptureGuard, Rx) {
48 let (mut writer, rx) = Tee::stdout();
50 if env::var("VERBOSE_TEST_LOGS").is_ok() {
51 eprintln!("Enabled verbose test logging.");
52 writer.loud();
53 } else {
54 eprintln!("To see full logs from this test set VERBOSE_TEST_LOGS=true");
55 }
56 let subscriber = tracing_subscriber::fmt()
57 .with_max_level(Level::TRACE)
58 .with_writer(Mutex::new(writer))
59 .finish();
60 let guard = tracing::subscriber::set_default(subscriber);
61 (LogCaptureGuard(guard), rx)
62}
63
64pub struct Rx(Arc<Mutex<Vec<u8>>>);
66impl Rx {
67 pub fn contents(&self) -> String {
72 String::from_utf8(self.0.lock().unwrap().clone()).unwrap()
73 }
74}
75
76struct Tee<W> {
77 buf: Arc<Mutex<Vec<u8>>>,
78 quiet: bool,
79 inner: W,
80}
81
82impl Tee<TestWriter> {
83 fn stdout() -> (Self, Rx) {
84 let buf: Arc<Mutex<Vec<u8>>> = Default::default();
85 (
86 Tee {
87 buf: buf.clone(),
88 quiet: true,
89 inner: TestWriter::new(),
90 },
91 Rx(buf),
92 )
93 }
94}
95
96impl<W> Tee<W> {
97 fn loud(&mut self) {
98 self.quiet = false;
99 }
100}
101
102impl<W> Write for Tee<W>
103where
104 W: Write,
105{
106 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
107 self.buf.lock().unwrap().extend_from_slice(buf);
108 if !self.quiet {
109 self.inner.write_all(buf)?;
110 Ok(buf.len())
111 } else {
112 Ok(buf.len())
113 }
114 }
115
116 fn flush(&mut self) -> std::io::Result<()> {
117 self.inner.flush()
118 }
119}