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}