ts_init/
lib.rs

1//! Initializes logging based on the specified environment and output configurations.
2//!
3//! This function configures the global logging behavior according to the specified outputs
4//! and the environment string provided. It supports conditional logging to `stderr`, files,
5//! or `journald` based on the inputs.
6//!
7//! # Arguments
8//! * `outputs` - A vector of `Option<String>` where each element represents an optional
9//!   output destination. Supported values are file paths and "journald".
10//! * `env` - A string slice that represents the logging environment. It can be a simple
11//!   level string like "debug" or a detailed filter like "my_crate=info,my_crate::module=debug".
12//!
13//! # Examples
14//! ```
15//! init_logging(vec![None, Some("log.log".to_string())], "debug");
16//! init_logging(vec![None, Some("journald".to_string())], "debug");
17//! init_logging(vec![Some("journald".to_string())], "debug");
18//! ```
19//!
20//! # Panics
21//! This function panics if the `outputs` vector has more than two elements or if the specified
22//! logging configuration is invalid.
23//!
24//! # Errors
25//! This function sets the global default logger and may return an error if logging initialization
26//! fails due to system-level constraints or invalid configurations.
27pub fn init_logging<S: AsRef<str>>(outputs: Vec<Option<String>>, env: S) {
28    use tracing::subscriber::set_global_default;
29    //use tracing_subscriber::{fmt, layer::SubscriberExt, EnvFilter};
30    use tracing_subscriber::{layer::SubscriberExt, *};
31
32    let default_env = env.as_ref();
33
34    fn file_appender(path: impl AsRef<str>) -> std::fs::File {
35        std::fs::File::options()
36            .append(true)
37            .create(true)
38            .open(path.as_ref())
39            .unwrap_or_else(|e| panic!("{:?}: {}", path.as_ref(), e))
40    }
41
42    let t = tracing_subscriber::fmt()
43        .with_env_filter(
44            EnvFilter::try_from_default_env()
45                .unwrap_or_else(|_| EnvFilter::builder().parse(default_env).unwrap()),
46        )
47        .with_writer(std::io::stderr);
48
49    match outputs.len() {
50        0 => set_global_default(t.finish()),
51        1 => match outputs[0].as_ref() {
52            None => set_global_default(t.finish()),
53            Some(p) => match p.as_str() {
54                "journald" => {
55                    set_global_default(Registry::default().with(tracing_journald::layer().unwrap()))
56                }
57                _ => set_global_default(t.with_writer(file_appender(p)).with_ansi(false).finish()),
58            },
59        },
60        2 => match (outputs[0].as_ref(), outputs[1].as_ref()) {
61            (None, Some(p)) => match p.as_str() {
62                "journald" => {
63                    set_global_default(t.finish().with(tracing_journald::layer().unwrap()))
64                }
65                _ => set_global_default(
66                    t.finish().with(
67                        fmt::Layer::default()
68                            .with_writer(file_appender(p))
69                            .with_ansi(false),
70                    ),
71                ),
72            },
73            _ => panic!("Invalid output"),
74        },
75        _ => panic!("Too many outputs"),
76    }
77    .unwrap();
78}
79
80/// create env string from CARGO_PKG_NAME and CARGO_BIN_NAME with given log level
81#[macro_export]
82macro_rules! crate_env {
83    ($env:expr) => {
84        format!(
85            "{}={},{}={}",
86            env!("CARGO_PKG_NAME").replace('-', "_"),
87            $env,
88            env!("CARGO_BIN_NAME").replace('-', "_"),
89            $env
90        )
91    };
92}