init_log4rs/
init_log4rs.rs1use std::env;
2use std::fs;
3use std::fs::File;
4use std::io::prelude::*;
5use std::path::PathBuf;
6
7use log4rs;
8use thiserror::Error;
9
10#[derive(Debug, Error)]
11pub enum InitLog4rsError {
12 #[error(transparent)]
13 Anyhow(#[from] anyhow::Error),
14 #[error(transparent)]
15 IoError(#[from] std::io::Error),
16
17 #[error("{0}")]
18 Other(String),
19}
20
21pub fn init_log4rs(log_cfg_yaml: &str, log_stem: &str) -> Result<(), InitLog4rsError> {
28 let mut log_path: Vec<PathBuf> = Vec::new();
29
30 if let Ok(log_dir) = env::var("RUST_LOG_DIR") {
32 log_path.push(PathBuf::from(log_dir));
33 }
34
35 if let Ok(exe) = std::env::current_exe()
36 && let Some(p) = exe.parent()
37 {
38 let mut exe_log_dir = p.to_path_buf();
39 exe_log_dir.push("logs");
40 log_path.push(exe_log_dir);
41 }
42 if let Ok(mut pwd) = env::current_dir() {
43 pwd.push("logs");
44 log_path.push(pwd);
45 }
46 if let Ok(pwd) = env::current_dir()
47 && let Some(parent) = pwd.parent()
48 {
49 let mut path = parent.to_path_buf();
50 path.push("logs");
51 log_path.push(path);
52 }
53 if let Some(mut path) = dirs::home_dir() {
54 path.push("logs");
55 log_path.push(path);
56 }
57 let mut temp_log_dir = env::temp_dir();
58 temp_log_dir.push("logs");
59 log_path.push(temp_log_dir);
60
61 for path in &log_path {
63 let mut log_cfg_file = path.clone();
64 log_cfg_file.push(log_cfg_yaml);
65 match log4rs::init_file(log_cfg_file.clone(), Default::default()) {
66 Ok(_) => {
67 eprintln!("Log dir {}", path.display());
68 return Ok(());
69 }
70 Err(_err) => {
71 }
73 }
74 }
75
76 for path in log_path.iter() {
78 match logger_yaml_file_create(path, log_cfg_yaml, log_stem) {
79 Ok(_) => {
80 eprintln!("Log dir {}", path.display());
81 return Ok(());
82 }
83 Err(_err) => {
84 }
86 }
87 }
88 return Err(InitLog4rsError::Other(
89 "Failed to initialize log4rs.".to_string(),
90 ));
91}
92
93fn logger_yaml_file_create(
95 path: &PathBuf,
96 log_cfg: &str,
97 log_stem: &str,
98) -> Result<(), InitLog4rsError> {
99 fs::create_dir_all(path)?;
100
101 let mut log_store = path.clone();
102 log_store.push(log_stem);
103 log_store.set_extension("log");
104 let log_store_file = log_store.to_str().ok_or(InitLog4rsError::Other(
105 "log store path construct fail".to_string(),
106 ))?;
107
108 let mut log_tar = path.clone();
109 log_tar.push(log_stem);
110 log_tar.set_extension("log.{}");
111
112 let log_tar_file = log_tar.to_str().ok_or(InitLog4rsError::Other(
113 "log tar path construct fail".to_string(),
114 ))?;
115
116 let mut log_cfg_file = PathBuf::from(path);
117 log_cfg_file.push(log_cfg);
118
119 let config_str = format!(
120 "
121# Scan this file for changes every 30 seconds
122refresh_rate: 60 seconds
123
124appenders:
125 # stdout
126 stdout:
127 kind: console
128
129 # stderr
130 stderr:
131 kind: console
132 target: stderr
133
134 # rolling_file
135 rolling_file:
136 kind: rolling_file
137 path: {}
138 append: true
139 encoder:
140 # https://docs.rs/log4rs/1.0.0/log4rs/encode/pattern/index.html#formatters
141 pattern: '{{d}} {{l}} {{M}}:{{L}} - {{m}}{{n}}' # Date Level [Module]:[line] - msg \\n
142 policy:
143 kind: compound
144 trigger:
145 kind: size
146 limit: 10 mb # file size limit 102400 Byte
147 roller:
148 kind: fixed_window
149 pattern: {}
150 base: 1
151 count: 20
152
153# loggers:
154# map_app::my_mod: # custom logger
155# level: debug
156# appenders:
157# - stderr
158# additive: false
159
160# Set the default logging level to 'info' and attach the 'rolling_file' appender to the root
161root:
162 level: info
163 appenders:
164 - rolling_file
165",
166 log_store_file, log_tar_file
167 );
168
169 let mut output = File::create(log_cfg_file.clone())?;
171 write!(output, "{}", config_str)?;
172 drop(output);
173 log4rs::init_file(log_cfg_file, Default::default())?;
174 Ok(())
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180
181 #[test]
182 fn test_log4rs() -> anyhow::Result<()> {
183 init_log4rs("log4rs.yaml", "app_log")?;
184 Ok(())
185 }
186}