1use std::sync::Mutex;
4
5use anyhow::{Context, Result};
6use wowlab_fs::{file::File, path::PathBuf, temporary};
7
8pub(crate) fn init_trace_log(enabled: bool, label: &str) -> Result<Option<PathBuf>> {
9 if !enabled {
10 return Ok(None);
11 }
12
13 let file = create_trace_log(label)?;
14 let path = file.path().to_path_buf();
15 let subscriber = tracing_subscriber::fmt()
16 .with_max_level(tracing::Level::TRACE)
17 .with_writer(Mutex::new(file))
18 .with_ansi(false)
19 .finish();
20
21 tracing::subscriber::set_global_default(subscriber)
22 .context("failed to set tracing subscriber")?;
23
24 Ok(Some(path))
25}
26
27fn create_trace_log(label: &str) -> Result<File> {
28 let temporary = temporary::File::with_affixes(&format!("forge-trace-{label}-"), ".log")
29 .context("failed to create trace log")?;
30
31 temporary.retain().context("failed to create trace log")
32}
33
34#[cfg(test)]
35mod tests {
36 use std::io::Write as _;
37
38 use googletest::prelude::*;
39 use wowlab_fs::{directory, file};
40
41 use super::create_trace_log;
42
43 #[gtest]
44 fn trace_logs_are_unique_named_and_retained_after_the_writer_closes() -> Result<()> {
45 let mut left = create_trace_log("outlaw_rogue").or_fail()?;
46 let right = create_trace_log("outlaw_rogue").or_fail()?;
47 let left_path = left.path().to_path_buf();
48 let right_path = right.path().to_path_buf();
49 let left_name = left_path
50 .file_name()
51 .and_then(|name| name.to_str())
52 .or_fail()?;
53 let left_extension = left_path.extension().and_then(|value| value.to_str());
54
55 left.write_all(b"trace event").or_fail()?;
56 left.sync().or_fail()?;
57
58 verify_that!(left_path, not(eq(&right_path)))?;
59 verify_true!(left_name.starts_with("forge-trace-outlaw_rogue-"))?;
60 verify_eq!(left_extension, Some("log"))?;
61
62 drop(left);
63 drop(right);
64
65 verify_that!(file::read_text(&left_path).or_fail()?, eq("trace event"))?;
66 verify_that!(directory::inspect(&right_path).or_fail()?, some(anything()))?;
67
68 directory::remove_file_if_exists(&left_path).or_fail()?;
69 directory::remove_file_if_exists(&right_path).or_fail()?;
70
71 Ok(())
72 }
73}