ducker/
tracing.rs

1use std::path::PathBuf;
2
3use color_eyre::eyre::Result;
4use lazy_static::lazy_static;
5use tracing::info;
6use tracing_error::ErrorLayer;
7use tracing_subscriber::{self, layer::SubscriberExt, util::SubscriberInitExt};
8
9use crate::config::get_app_config_path;
10
11// taken form https://ratatui.rs/recipes/apps/log-with-tracing/
12
13lazy_static! {
14    pub static ref PROJECT_NAME: String = env!("CARGO_CRATE_NAME").to_uppercase().to_string();
15    pub static ref LOG_ENV: String = format!("{}_LOGLEVEL", PROJECT_NAME.clone());
16    pub static ref LOG_FILE: String = format!("{}.log", env!("CARGO_PKG_NAME"));
17}
18
19fn project_directory() -> Option<PathBuf> {
20    dirs_next::data_dir().map(|data_dir| data_dir.join(env!("CARGO_CRATE_NAME")))
21}
22
23pub fn get_log_dir() -> PathBuf {
24    if let Some(p) = project_directory() {
25        p
26    } else if let Ok(p) = get_app_config_path() {
27        p
28    } else {
29        PathBuf::from(".").join(".data")
30    }
31}
32
33pub fn initialize_logging(log_to: &Option<PathBuf>) -> Result<()> {
34    let log_path = match log_to {
35        Some(p) => p.clone(),
36        None => {
37            let directory = get_log_dir();
38            std::fs::create_dir_all(directory.clone())?;
39            directory.join(LOG_FILE.clone())
40        }
41    };
42
43    let log_file = std::fs::File::create(log_path)?;
44    std::env::set_var(
45        "RUST_LOG",
46        std::env::var("RUST_LOG")
47            .or_else(|_| std::env::var(LOG_ENV.clone()))
48            .unwrap_or_else(|_| format!("{}=info", env!("CARGO_CRATE_NAME"))),
49    );
50    let file_subscriber = tracing_subscriber::fmt::layer()
51        .with_file(true)
52        .with_line_number(true)
53        .with_writer(log_file)
54        .with_target(false)
55        .with_ansi(false);
56    tracing_subscriber::registry()
57        .with(file_subscriber)
58        .with(ErrorLayer::default())
59        .with(tracing_subscriber::filter::EnvFilter::from_default_env())
60        .init();
61
62    info!("logging initialised");
63    Ok(())
64}
65
66/// Similar to the `std::dbg!` macro, but generates `tracing` events rather
67/// than printing to stdout.
68///
69/// By default, the verbosity level for the generated events is `DEBUG`, but
70/// this can be customized.
71#[macro_export]
72macro_rules! trace_dbg {
73    (target: $target:expr, level: $level:expr, $ex:expr) => {{
74        match $ex {
75            value => {
76                tracing::event!(target: $target, $level, ?value, stringify!($ex));
77                value
78            }
79        }
80    }};
81    (level: $level:expr, $ex:expr) => {
82        trace_dbg!(target: module_path!(), level: $level, $ex)
83    };
84    (target: $target:expr, $ex:expr) => {
85        trace_dbg!(target: $target, level: tracing::Level::DEBUG, $ex)
86    };
87    ($ex:expr) => {
88        trace_dbg!(level: tracing::Level::DEBUG, $ex)
89    };
90}