use crate::*;
use log::Level;
use std::path;
use std::path::{Path, PathBuf};
use std::str::FromStr;
pub const DEFAULT_TIME: &'static str = "%Y-%m-%d %H:%M:%S%.6f";
pub const LOG_FORMAT_DEBUG: LogFormat = LogFormat::new(DEFAULT_TIME, debug_format_f);
pub const LOG_FORMAT_THREADED_DEBUG: LogFormat =
LogFormat::new(DEFAULT_TIME, threaded_debug_format_f);
pub const LOG_FORMAT_PROD: LogFormat = LogFormat::new(DEFAULT_TIME, prod_format_f);
pub fn debug_format_f(r: FormatRecord) -> String {
let time = r.time();
let level = r.level();
let file = r.file();
let line = r.line();
let msg = r.msg();
format!("[{time}][{level}][{file}:{line}] {msg}\n").to_string()
}
pub fn threaded_debug_format_f(r: FormatRecord) -> String {
let time = r.time();
let level = r.level();
let file = r.file();
let line = r.line();
let msg = r.msg();
let thread_id = r.thread_id();
format!("[{time}][{level}][{:?}][{file}:{line}] {msg}\n", thread_id).to_string()
}
pub fn prod_format_f(r: FormatRecord) -> String {
let time = r.time();
let level = r.level();
let msg = r.msg();
format!("[{time}][{level}] {msg}\n").to_string()
}
pub fn console_logger(target: ConsoleTarget, max_level: Level) -> Builder {
let console_config = LogConsole::new(target, max_level, LOG_FORMAT_DEBUG);
return Builder::default().add_sink(console_config);
}
#[inline]
pub fn stdout_logger(max_level: Level) -> Builder {
console_logger(ConsoleTarget::Stdout, max_level).test()
}
#[inline]
pub fn stderr_logger(max_level: Level) -> Builder {
console_logger(ConsoleTarget::Stderr, max_level).test()
}
pub fn env_logger(file_env_name: &str, level_env_name: &str) -> Builder {
let level: Level = crate::env::env_or(level_env_name, Level::Info).into();
let mut console: Option<ConsoleTarget> = None;
if let Ok(file_path) = std::env::var(file_env_name) {
if let Ok(target) = ConsoleTarget::from_str(file_path.as_str()) {
console = Some(target);
} else if file_path.len() > 0 {
return raw_file_logger(file_path, level).test();
}
}
return console_logger(console.unwrap_or(ConsoleTarget::Stderr), level).test();
}
pub fn raw_file_logger_custom<P: Into<PathBuf>>(
file_path: P, max_level: Level, time_fmt: &'static str, format_func: FormatFunc,
) -> Builder {
let format = LogFormat::new(time_fmt, format_func);
let _file_path = file_path.into();
let p = path::absolute(&_file_path).expect("path convert to absolute");
let dir = p.parent().unwrap();
let file_name = Path::new(p.file_name().unwrap());
let file = LogRawFile::new(dir, file_name, max_level, format);
return Builder::default().signal(signal_hook::consts::SIGUSR1).add_sink(file);
}
pub fn raw_file_logger<P: Into<PathBuf>>(file_path: P, max_level: Level) -> Builder {
raw_file_logger_custom(file_path, max_level, DEFAULT_TIME, debug_format_f)
}
pub fn split_error_file_logger<P1, P2>(dir: P1, name: P2, max_level: Level) -> Builder
where
P1: Into<PathBuf>,
P2: Into<String>,
{
let _name: String = name.into();
let debug_file_name = format!("{}.log", _name);
let _dir: PathBuf = dir.into();
let debug_file = LogRawFile::new(_dir.clone(), debug_file_name, max_level, LOG_FORMAT_DEBUG);
let err_file_name = format!("{}.log.wf", _name);
let error_file = LogRawFile::new(_dir.clone(), err_file_name, Level::Error, LOG_FORMAT_PROD);
return Builder::default()
.signal(signal_hook::consts::SIGUSR1)
.add_sink(debug_file)
.add_sink(error_file);
}
pub fn buffered_file_logger_custom<P: Into<PathBuf>>(
file_path: P, max_level: Level, time_fmt: &'static str, format_func: FormatFunc,
flush_millis: usize, rotate: Option<crate::rotation::Rotation>,
) -> Builder {
let format = LogFormat::new(time_fmt, format_func);
let _file_path = file_path.into();
let p = path::absolute(&_file_path).expect("path convert to absolute");
let dir = p.parent().unwrap();
let file_name = Path::new(p.file_name().unwrap());
let mut file = LogBufFile::new(dir, file_name, max_level, format, flush_millis);
if let Some(ro) = rotate {
file = file.rotation(ro);
}
return Builder::default().signal(signal_hook::consts::SIGUSR1).add_sink(file);
}
pub fn buffered_file_logger<P: Into<PathBuf>>(file_path: P, max_level: Level) -> Builder {
buffered_file_logger_custom(file_path, max_level, DEFAULT_TIME, debug_format_f, 0, None)
}
pub fn buffered_rotated_file_logger<P: Into<PathBuf>>(
file_path: P, max_level: Level, rotation: crate::rotation::Rotation,
) -> Builder {
buffered_file_logger_custom(
file_path,
max_level,
DEFAULT_TIME,
debug_format_f,
0,
Some(rotation),
)
}
#[cfg(feature = "syslog")]
#[cfg_attr(docsrs, doc(cfg(feature = "syslog")))]
pub fn syslog_local(facility: syslog::Facility, max_level: Level) -> Builder {
let syslog = syslog::Syslog::new(facility, max_level);
return Builder::default().add_sink(syslog);
}
#[cfg(feature = "ringfile")]
#[cfg_attr(docsrs, doc(cfg(feature = "ringfile")))]
pub fn ring_file<P: Into<PathBuf>>(
file_path: P, buf_size: i32, max_level: Level, dump_signal: i32,
) -> Builder {
let ring =
ringfile::LogRingFile::new(file_path, buf_size, max_level, LOG_FORMAT_THREADED_DEBUG);
let mut config = Builder::default().signal(dump_signal).add_sink(ring);
config.dynamic = true;
config
}