1use crate::*;
9use log::Level;
10use std::path;
11use std::path::{Path, PathBuf};
12use std::str::FromStr;
13
14pub const DEFAULT_TIME: &'static str = "%Y-%m-%d %H:%M:%S%.6f";
15
16pub const LOG_FORMAT_DEBUG: LogFormat = LogFormat::new(DEFAULT_TIME, debug_format_f);
18
19pub const LOG_FORMAT_THREADED_DEBUG: LogFormat =
21 LogFormat::new(DEFAULT_TIME, threaded_debug_format_f);
22
23pub const LOG_FORMAT_PROD: LogFormat = LogFormat::new(DEFAULT_TIME, prod_format_f);
25
26pub fn debug_format_f(r: FormatRecord) -> String {
28 let time = r.time();
29 let level = r.level();
30 let file = r.file();
31 let line = r.line();
32 let msg = r.msg();
33 format!("[{time}][{level}][{file}:{line}] {msg}\n").to_string()
34}
35
36pub fn threaded_debug_format_f(r: FormatRecord) -> String {
38 let time = r.time();
39 let level = r.level();
40 let file = r.file();
41 let line = r.line();
42 let msg = r.msg();
43 let thread_id = r.thread_id();
44 format!("[{time}][{level}][{:?}][{file}:{line}] {msg}\n", thread_id).to_string()
45}
46
47pub fn prod_format_f(r: FormatRecord) -> String {
49 let time = r.time();
50 let level = r.level();
51 let msg = r.msg();
52 format!("[{time}][{level}] {msg}\n").to_string()
53}
54
55pub fn console_logger(target: ConsoleTarget, max_level: Level) -> Builder {
56 let console_config = LogConsole::new(target, max_level, LOG_FORMAT_DEBUG);
57 return Builder::default().add_sink(console_config);
58}
59
60#[inline]
64pub fn stdout_logger(max_level: Level) -> Builder {
65 console_logger(ConsoleTarget::Stdout, max_level).test()
66}
67
68#[inline]
72pub fn stderr_logger(max_level: Level) -> Builder {
73 console_logger(ConsoleTarget::Stderr, max_level).test()
74}
75
76pub fn env_logger(file_env_name: &str, level_env_name: &str) -> Builder {
97 let level: Level = crate::env::env_or(level_env_name, Level::Info).into();
98 let mut console: Option<ConsoleTarget> = None;
99 if let Ok(file_path) = std::env::var(file_env_name) {
100 if let Ok(target) = ConsoleTarget::from_str(file_path.as_str()) {
101 console = Some(target);
102 } else if file_path.len() > 0 {
103 return raw_file_logger(file_path, level).test();
104 }
105 }
106 return console_logger(console.unwrap_or(ConsoleTarget::Stderr), level).test();
107}
108
109pub fn raw_file_logger_custom<P: Into<PathBuf>>(
121 file_path: P, max_level: Level, time_fmt: &'static str, format_func: FormatFunc,
122) -> Builder {
123 let format = LogFormat::new(time_fmt, format_func);
124 let _file_path = file_path.into();
125 let p = path::absolute(&_file_path).expect("path convert to absolute");
126 let dir = p.parent().unwrap();
127 let file_name = Path::new(p.file_name().unwrap());
128 let file = LogRawFile::new(dir, file_name, max_level, format);
129 return Builder::default().signal(signal_hook::consts::SIGUSR1).add_sink(file);
130}
131
132pub fn raw_file_logger<P: Into<PathBuf>>(file_path: P, max_level: Level) -> Builder {
140 raw_file_logger_custom(file_path, max_level, DEFAULT_TIME, debug_format_f)
141}
142
143pub fn split_error_file_logger<P1, P2>(dir: P1, name: P2, max_level: Level) -> Builder
155where
156 P1: Into<PathBuf>,
157 P2: Into<String>,
158{
159 let _name: String = name.into();
160 let debug_file_name = format!("{}.log", _name);
161 let _dir: PathBuf = dir.into();
162 let debug_file = LogRawFile::new(_dir.clone(), debug_file_name, max_level, LOG_FORMAT_DEBUG);
163 let err_file_name = format!("{}.log.wf", _name);
164 let error_file = LogRawFile::new(_dir.clone(), err_file_name, Level::Error, LOG_FORMAT_PROD);
165
166 return Builder::default()
167 .signal(signal_hook::consts::SIGUSR1)
168 .add_sink(debug_file)
169 .add_sink(error_file);
170}
171
172pub fn buffered_file_logger_custom<P: Into<PathBuf>>(
186 file_path: P, max_level: Level, time_fmt: &'static str, format_func: FormatFunc,
187 flush_millis: usize, rotate: Option<crate::rotation::Rotation>,
188) -> Builder {
189 let format = LogFormat::new(time_fmt, format_func);
190 let _file_path = file_path.into();
191 let p = path::absolute(&_file_path).expect("path convert to absolute");
192 let dir = p.parent().unwrap();
193 let file_name = Path::new(p.file_name().unwrap());
194 let mut file = LogBufFile::new(dir, file_name, max_level, format, flush_millis);
195 if let Some(ro) = rotate {
196 file = file.rotation(ro);
197 }
198 return Builder::default().signal(signal_hook::consts::SIGUSR1).add_sink(file);
199}
200
201pub fn buffered_file_logger<P: Into<PathBuf>>(file_path: P, max_level: Level) -> Builder {
209 buffered_file_logger_custom(file_path, max_level, DEFAULT_TIME, debug_format_f, 0, None)
210}
211
212pub fn buffered_rotated_file_logger<P: Into<PathBuf>>(
222 file_path: P, max_level: Level, rotation: crate::rotation::Rotation,
223) -> Builder {
224 buffered_file_logger_custom(
225 file_path,
226 max_level,
227 DEFAULT_TIME,
228 debug_format_f,
229 0,
230 Some(rotation),
231 )
232}
233
234#[cfg(feature = "syslog")]
236#[cfg_attr(docsrs, doc(cfg(feature = "syslog")))]
237pub fn syslog_local(facility: syslog::Facility, max_level: Level) -> Builder {
238 let syslog = syslog::Syslog::new(facility, max_level);
239 return Builder::default().add_sink(syslog);
240}
241
242#[cfg(feature = "ringfile")]
258#[cfg_attr(docsrs, doc(cfg(feature = "ringfile")))]
259pub fn ring_file<P: Into<PathBuf>>(
260 file_path: P, buf_size: i32, max_level: Level, dump_signal: i32,
261) -> Builder {
262 let ring =
263 ringfile::LogRingFile::new(file_path, buf_size, max_level, LOG_FORMAT_THREADED_DEBUG);
264 let mut config = Builder::default().signal(dump_signal).add_sink(ring);
265 config.dynamic = true;
266 config
267}