Skip to main content

env_tracing_logger/
lib.rs

1// Copyright (C) The Strand-Braid Authors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use time::{UtcOffset, format_description::well_known::Iso8601};
5use tracing_subscriber::{
6    fmt::{self, time::OffsetTime},
7    layer::SubscriberExt,
8};
9
10struct Guard {}
11
12impl Drop for Guard {
13    fn drop(&mut self) {}
14}
15
16pub fn init() -> impl Drop {
17    initiate_logging::<&str>(None, false).unwrap()
18}
19
20/// Start logging to file and console, both optional.
21pub fn initiate_logging<P: AsRef<std::path::Path>>(
22    path: Option<P>,
23    disable_console: bool,
24) -> Result<impl Drop, Box<dyn std::error::Error + Send + Sync + 'static>> {
25    // Create a fixed offset time formatter based on the timezone at the
26    // time this line of code runs.
27    let timer = OffsetTime::new(
28        UtcOffset::from_whole_seconds(chrono::Local::now().offset().local_minus_utc())?,
29        Iso8601::DEFAULT,
30    );
31
32    let file_layer = if let Some(path) = &path {
33        let file = std::fs::File::create(path)?;
34        let file_writer = std::sync::Mutex::new(file);
35        Some(
36            fmt::layer()
37                .with_timer(timer.clone())
38                .with_writer(file_writer)
39                .with_ansi(false)
40                .with_file(true)
41                .with_line_number(true),
42        )
43    } else {
44        None
45    };
46
47    let console_layer = if disable_console {
48        None
49    } else {
50        #[cfg(target_os = "windows")]
51        let with_ansi = match ansi_term::enable_ansi_support() {
52            Ok(_) => true,
53            Err(code) => {
54                tracing::error!("Failed setting windows ansi: {code}");
55                false
56            }
57        };
58        #[cfg(not(target_os = "windows"))]
59        let with_ansi = true;
60
61        Some(
62            fmt::layer()
63                .with_timer(timer)
64                .with_ansi(with_ansi)
65                .with_file(true)
66                .with_line_number(true),
67        )
68    };
69
70    let collector = tracing_subscriber::registry()
71        .with(file_layer)
72        .with(console_layer)
73        .with(tracing_subscriber::filter::EnvFilter::from_default_env());
74    tracing::subscriber::set_global_default(collector)?;
75
76    let log_var = if let Ok(var) = std::env::var("RUST_LOG") {
77        format!(" with RUST_LOG=\"{var}\".")
78    } else {
79        ".".to_string()
80    };
81
82    if let Some(path) = &path {
83        tracing::debug!(
84            "Logging initiated to file \"{}\"{log_var}",
85            path.as_ref().display(),
86        );
87    }
88
89    if !disable_console {
90        tracing::debug!("Logging initiated to console{log_var}",);
91    }
92
93    Ok(Guard {})
94}