use std::{env, vec};
use crate::{dev_or_prod, string::StringExentd, IResult};
use log::LevelFilter;
use once_cell::sync::Lazy;
pub static EXE_FILE_NAME: Lazy<String> = Lazy::new(|| {
let mut filename = std::env::current_exe()
.unwrap_or_default()
.as_path()
.file_name()
.map(|x| x.to_str().map(|x| x.to_string()))
.unwrap_or_default()
.unwrap_or_default();
if filename.find(|x| x == '.').is_some() {
let (filename2, _) = filename.split_char2(".");
filename = filename2;
}
filename
});
pub fn init() -> IResult {
use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller;
use log4rs::append::rolling_file::policy::compound::trigger::size::SizeTrigger;
use log4rs::append::rolling_file::policy::compound::CompoundPolicy;
use log4rs::{
append::{
console::{ConsoleAppender, Target},
rolling_file::RollingFileAppender,
},
config::{Appender, Root},
encode::pattern::PatternEncoder,
filter::threshold::ThresholdFilter,
};
let dir = format!("logs-{}", EXE_FILE_NAME.to_string());
println!("logs path: {}", dir);
let parttern = "{d(%Y-%m-%d %H:%M:%S.%6f)} {l} [{f}:{L}] {m}\n";
let file_size = 1024 * 1024 * 100;
let logfile_get = |filter: log::LevelFilter, level_name: &str| {
let builder = RollingFileAppender::builder()
.encoder(Box::new(PatternEncoder::new(parttern)))
.build(
format!("{dir}/{level_name}.log"),
Box::new(CompoundPolicy::new(
Box::new(SizeTrigger::new(file_size)),
Box::new(FixedWindowRoller::builder().base(1).build(format!("{dir}/{level_name}.{{}}.log").as_str(), 30).unwrap()),
)),
)
.unwrap();
Appender::builder().filter(Box::new(ThresholdFilter::new(filter))).build(level_name, Box::new(builder))
};
let mut appenders = vec!["debug", "info", "warn", "error"];
if dev_or_prod!(true, false) {
appenders.push("console");
}
let config = log4rs::Config::builder()
.appender(logfile_get(log::LevelFilter::Debug, "debug"))
.appender(logfile_get(log::LevelFilter::Info, "info"))
.appender(logfile_get(log::LevelFilter::Warn, "warn"))
.appender(logfile_get(log::LevelFilter::Error, "error"))
.appender(Appender::builder().filter(Box::new(ThresholdFilter::new(log::LevelFilter::Debug))).build(
"console",
Box::new(ConsoleAppender::builder().encoder(Box::new(PatternEncoder::new(parttern))).target(Target::Stdout).build()),
))
.logger(log4rs::config::Logger::builder().build("ureq", LevelFilter::Info))
.logger(log4rs::config::Logger::builder().build("rbatis", dev_or_prod!(LevelFilter::Info, LevelFilter::Warn)))
.logger(log4rs::config::Logger::builder().build("rustls", LevelFilter::Info))
.logger(log4rs::config::Logger::builder().build("reqwest", LevelFilter::Info))
.logger(log4rs::config::Logger::builder().build("hyper", LevelFilter::Info))
.logger(log4rs::config::Logger::builder().build("sled", LevelFilter::Info))
.logger(log4rs::config::Logger::builder().build("isahc", LevelFilter::Warn))
.logger(log4rs::config::Logger::builder().build("mqtt_async_client", LevelFilter::Warn))
.logger(log4rs::config::Logger::builder().build("teloxide", LevelFilter::Off))
.logger(log4rs::config::Logger::builder().build("tao::platform_impl", LevelFilter::Error))
.build(Root::builder().appenders(appenders).build(log::LevelFilter::Debug))
.unwrap();
log4rs::init_config(config)?;
Ok(())
}
pub fn init_by_off(off_libs: impl Into<String>) -> IResult {
let name = EXE_FILE_NAME.to_string();
init_by_off2(off_libs, name)
}
pub fn init_by_off2(off_libs: impl Into<String>, log_name: impl Into<String>) -> IResult {
init3(off_libs, log_name, true)
}
pub fn init3(off_libs: impl Into<String>, log_name: impl Into<String>, foce_write_to_file: bool) -> IResult {
let off_libs = off_libs.into();
use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller;
use log4rs::append::rolling_file::policy::compound::trigger::size::SizeTrigger;
use log4rs::append::rolling_file::policy::compound::CompoundPolicy;
use log4rs::{
append::{
console::{ConsoleAppender, Target},
rolling_file::RollingFileAppender,
},
config::{Appender, Root},
encode::pattern::PatternEncoder,
filter::threshold::ThresholdFilter,
};
let dir = format!("logs-{}", log_name.into());
println!("logs path: {}", dir);
let parttern = "{d(%Y-%m-%d %H:%M:%S.%6f)} {l} [{f}:{L}] {m}\n";
let file_size = 1024 * 1024 * 100;
let mut appenders = vec!["console".to_string()];
let mut logfile_get = |filter: log::LevelFilter| {
let level_name = filter.as_str().to_lowercase();
let builder = RollingFileAppender::builder()
.encoder(Box::new(PatternEncoder::new(parttern)))
.build(
format!("{dir}/{level_name}.log"),
Box::new(CompoundPolicy::new(
Box::new(SizeTrigger::new(file_size)),
Box::new(FixedWindowRoller::builder().base(1).build(format!("{dir}/{level_name}.{{}}.log").as_str(), 30).unwrap()),
)),
)
.unwrap();
let level_name = format!("file_{level_name}");
appenders.push(level_name.clone());
Appender::builder().filter(Box::new(ThresholdFilter::new(filter))).build(level_name, Box::new(builder))
};
let log_level = env::var("RUST_LOG").unwrap_or_else(|_| if cfg!(debug_assertions) { "debug".to_string() } else { "warn".to_string() });
let log_level = log_level.split(",").map(|x| x.trim().to_string()).collect::<Vec<String>>();
let console_level = log_level[0].trim().to_uppercase().parse::<log::LevelFilter>().unwrap_or(log::LevelFilter::Warn);
if console_level == log::LevelFilter::Off {
return Ok(());
}
let mut config = log4rs::Config::builder().appender(Appender::builder().filter(Box::new(ThresholdFilter::new(console_level))).build(
"console",
Box::new(ConsoleAppender::builder().encoder(Box::new(PatternEncoder::new(parttern))).target(Target::Stdout).build()),
));
let log_levels = [log::LevelFilter::Trace, log::LevelFilter::Debug, log::LevelFilter::Info, log::LevelFilter::Warn, log::LevelFilter::Error];
for l in log_levels {
if foce_write_to_file || console_level >= l {
config = config.appender(logfile_get(l));
}
}
if log_level.len() > 1 {
for i in 1..log_level.len() {
let (name, level) = log_level[i].split_char2("=");
let name = name.trim().to_string();
if name.is_empty() || level.is_empty() {
continue;
}
let level = level.trim().to_uppercase().parse::<log::LevelFilter>().unwrap_or(log::LevelFilter::Warn);
config = config.logger(log4rs::config::Logger::builder().build(name, level));
}
}
let offs = off_libs.split_char(",");
for off in offs {
if off.trim().is_empty() {
continue;
}
config = config.logger(log4rs::config::Logger::builder().build(off, LevelFilter::Off));
}
let config = config.build(Root::builder().appenders(appenders).build(log::LevelFilter::Trace))?;
log4rs::init_config(config)?;
Ok(())
}
#[test]
fn test() {
init().unwrap();
for i in 0..100 {
debug!("test debug log");
info!("test info log");
warn!("test warn log");
error!("test error log");
std::thread::sleep(std::time::Duration::from_millis(1000));
}
}
#[test]
fn test3() {
unsafe { std::env::set_var("RUST_LOG", "warn,reqwest2=debug") };
init3("reqwest,hyper,isahc".to_string(), "test".to_string(), false).unwrap();
for i in 0..10 {
debug!("test debug log {i}");
info!("test info log {i}");
warn!("test warn log {i}");
error!("test error log {i}");
std::thread::sleep(std::time::Duration::from_millis(200));
}
}