1use std::env;
24use std::io;
25use std::sync::Arc;
26use std::sync::Mutex;
27
28pub use ctor::ctor;
29use tracing_subscriber::fmt::format::FmtSpan;
30use tracing_subscriber::fmt::MakeWriter;
31use tracing_subscriber::fmt::Subscriber;
32use tracing_subscriber::EnvFilter;
33
34pub fn init() {
37 let env_name = ["SL_LOG", "RUST_LOG", "LOG"]
38 .into_iter()
39 .find(|name| env::var_os(name).is_some())
40 .unwrap_or("LOG");
41 let builder = Subscriber::builder()
42 .with_env_filter(EnvFilter::from_env(env_name))
43 .with_ansi(false)
44 .with_target(false)
45 .without_time()
46 .with_span_events(FmtSpan::ACTIVE);
47
48 builder.init();
49}
50
51pub fn traced(filter: &str, func: impl FnOnce()) -> Vec<String> {
54 #[derive(Clone, Default)]
55 struct Output(Arc<Mutex<Vec<String>>>);
56
57 impl MakeWriter<'_> for Output {
58 type Writer = Output;
59 fn make_writer(&self) -> Self::Writer {
60 self.clone()
61 }
62 }
63
64 impl io::Write for Output {
65 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
66 let mut lines = self.0.lock().unwrap();
67 let mut s = String::from_utf8_lossy(buf).trim().to_string();
68
69 if cfg!(fbcode_build) {
73 s = s.replace("_unittest: ", ": ");
74 s = s.replace("_unittest::", "::");
75 }
76
77 lines.push(s);
78 Ok(buf.len())
79 }
80 fn flush(&mut self) -> io::Result<()> {
81 Ok(())
82 }
83 }
84
85 let out = Output::default();
86 let builder = Subscriber::builder()
87 .with_env_filter(EnvFilter::new(filter))
88 .with_ansi(false)
89 .without_time()
90 .with_writer(out.clone())
91 .with_span_events(FmtSpan::ACTIVE);
92 let dispatcher = builder.finish();
93 tracing::subscriber::with_default(dispatcher, func);
94
95 let lines = out.0.lock().unwrap();
96 lines.clone()
97}
98
99#[macro_export]
101macro_rules! init {
102 () => {
103 #[dev_logger::ctor]
104 fn dev_logger_init_ctor() {
105 dev_logger::init();
106 }
107 };
108}
109
110#[test]
111fn test_traced() {
112 let lines = traced("info", || {
113 tracing::info_span!("bar", x = 1).in_scope(|| {
114 tracing::info!("foo");
115 tracing::debug!("foo2");
116 });
117 });
118 assert_eq!(
119 lines,
120 [
121 "INFO bar{x=1}: dev_logger: enter",
122 "INFO bar{x=1}: dev_logger: foo",
123 "INFO bar{x=1}: dev_logger: exit"
124 ]
125 );
126}