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