cli_log/init.rs
1use {
2 crate::file_logger::FileLogger,
3 log::LevelFilter,
4 std::{
5 env,
6 fs::File,
7 str::FromStr,
8 sync::Mutex,
9 },
10};
11
12/// Configure the application log according to env variable, without failing
13/// in case of io error.
14///
15/// If the log file cannot be created, the error is printed to stderr, then
16/// the application proceeds without logging.
17pub fn init(
18 app_name: &str,
19 app_version: &str,
20) {
21 if let Err(e) = try_init(app_name, app_version) {
22 eprintln!("Failed to initialize log: {}", e);
23 }
24}
25
26/// Configure the application log according to env variable.
27///
28/// If an io error occurs, it is returned, and all logging is disabled
29/// (but there won't be any panic or error on log calls).
30///
31/// The caller can decide to print the error and not, to continue or not.
32pub fn try_init(
33 app_name: &str,
34 app_version: &str,
35) -> std::io::Result<()> {
36 let env_var_name = format!("{}_LOG", app_name.to_ascii_uppercase().replace('-', "_"),);
37 let level = env::var(env_var_name).unwrap_or_else(|_| "off".to_string());
38 if level == "off" {
39 return Ok(());
40 }
41 if let Ok(level) = LevelFilter::from_str(&level) {
42 let log_file_name = format!("{}.log", app_name);
43 let file = File::create(log_file_name)?;
44 log::set_max_level(level);
45 let logger = FileLogger {
46 file: Mutex::new(file),
47 level,
48 };
49 log::set_boxed_logger(Box::new(logger)).unwrap();
50 log::info!(
51 "Starting {} v{} with log level {}",
52 app_name,
53 app_version,
54 level
55 );
56 }
57 Ok(())
58}
59
60/// Configure the application log according to env variable, without failing
61/// in case of io error.
62///
63/// If the log file cannot be created, the error is printed to stderr, then
64/// the application proceeds without logging.
65///
66/// Example:
67///
68/// ```
69/// cli_log::init_cli_log!();
70/// ```
71/// You may specify an altername application name instead
72/// of your crate name:
73///
74/// ```
75/// cli_log::init_cli_log!("my-app");
76/// ```
77///
78/// The application name will also be used to derive the
79/// env variable name giving the log level, for example
80/// `MY_APP_LOG=info` for an application named `my-app`.
81///
82/// The point of using this macro instead of the init function is to ensure
83/// `env!(CARGO_PKG_NAME)` and `env!(CARGO_PKG_VERSION)` are expanded for
84/// the outer package, not for cli-log
85#[macro_export]
86macro_rules! init_cli_log {
87 () => {
88 cli_log::init(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
89 };
90 ($app_name: expr) => {
91 cli_log::init($app_name, env!("CARGO_PKG_VERSION"));
92 };
93}
94
95/// Configure the application log according to env variable.
96///
97/// If an io error occurs, it is returned, and all logging is disabled
98/// (but there won't be any panic or error on log calls).
99///
100/// The caller can decide to print the error and not, to continue or not.
101///
102/// Example:
103///
104/// ```
105/// cli_log::try_init_cli_log!().expect("Failed to initialize log");
106/// ```
107/// You may specify an altername application name instead
108/// of your crate name:
109///
110/// ```
111/// if Err(e) = cli_log::try_init_cli_log!("my-app") {
112/// eprintln!("Running without log because of error: {}", e);
113/// }
114/// ```
115///
116/// The application name will also be used to derive the
117/// env variable name giving the log level, for example
118/// `MY_APP_LOG=info` for an application named `my-app`.
119///
120/// The point of using this macro instead of the init function is to ensure
121/// `env!(CARGO_PKG_NAME)` and `env!(CARGO_PKG_VERSION)` are expanded for
122/// the outer package, not for cli-log
123#[macro_export]
124macro_rules! try_init_cli_log {
125 () => {
126 cli_log::try_init(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
127 };
128 ($app_name: expr) => {
129 cli_log::try_init($app_name, env!("CARGO_PKG_VERSION"));
130 };
131}