1use std::path::{Path, PathBuf};
2use std::thread;
3use flexi_logger::{Cleanup, Criterion, DeferredNow, Duplicate, FileSpec, FlexiLoggerError, Naming, Record};
4
5fn custom_format(writer: &mut dyn std::io::Write, now: &mut DeferredNow, record: &Record) -> std::io::Result<()> {
6 let file = match record.file() {
7 None => {
8 "<unknown>".to_string()
9 }
10 Some(path) => {
11 Path::new(path).file_name().map(|v| v.to_string_lossy().to_string()).unwrap_or("<unknown>".to_string())
12 }
13 };
14 write!(
15 writer,
16 "{} [{}] [{}:{}] [{}] - {}",
17 now.format("%Y-%m-%d %H:%M:%S"),
18 record.level(),
19 file,
20 record.line().unwrap_or(0),
21 thread::current().name().unwrap_or(format!("{:?}", thread::current().id()).as_str()),
22 &record.args()
23 )
24}
25pub struct Logger {
26 app_name: String,
27 log_level: String,
28 log_to_file: bool,
29 log_path: PathBuf,
30 log_file_size: u64,
31 log_file_count: usize,
32 instance_id: String,
33 output_console: bool,
34}
35
36impl Logger {
37 pub fn new(app_name: &str) -> Self {
38 Self {
39 app_name: app_name.to_string(),
40 log_level: "info".to_string(),
41 log_to_file: false,
42 log_path: std::env::current_dir().unwrap().join("logs"),
43 log_file_size: 10 * 1024 * 1024,
44 log_file_count: 10,
45 instance_id: "".to_string(),
46 output_console: true,
47 }
48 }
49
50 pub fn set_instance_id(mut self, instance_id: &str) -> Self {
51 self.instance_id = instance_id.to_string();
52 self
53 }
54
55 pub fn set_process_id_to_instance_id(mut self) -> Self {
56 self.instance_id = format!("{}", std::process::id());
57 self
58 }
59
60 pub fn set_log_level(mut self, level: &str) -> Self {
61 self.log_level = level.to_string();
62 self
63 }
64
65 pub fn set_log_to_file(mut self, to_file: bool) -> Self {
66 self.log_to_file = to_file;
67 self
68 }
69
70 pub fn set_log_path(mut self, path: &str) -> Self {
71 self.log_path = PathBuf::from(path);
72 self
73 }
74
75 pub fn set_log_file_size(mut self, size: u64) -> Self {
76 self.log_file_size = size;
77 self
78 }
79
80 pub fn set_log_file_count(mut self, count: usize) -> Self {
81 self.log_file_count = count;
82 self
83 }
84
85 pub fn set_output_to_console(mut self, output_console: bool) -> Self {
86 self.output_console = output_console;
87 self
88 }
89
90 pub fn start(&self) -> Result<(), FlexiLoggerError> {
91 let mut logger = flexi_logger::Logger::try_with_env_or_str(self.log_level.as_str())?;
92 if self.log_to_file {
93 let mut base_name = self.app_name.clone();
94 if !self.instance_id.is_empty() {
95 base_name = format!("{}_{}", self.app_name, self.instance_id);
96 }
97 logger = logger.log_to_file(FileSpec::default().directory(self.log_path.as_path()).basename(base_name.as_str()))
98 .rotate(Criterion::Size(self.log_file_size), Naming::Numbers, Cleanup::KeepLogFiles(self.log_file_count), );
102 }
103 if !self.output_console {
104 logger = logger.duplicate_to_stderr(Duplicate::None);
105 } else {
106 logger = logger.duplicate_to_stderr(Duplicate::All);
107 }
108 logger.format(custom_format)
109 .start()?;
110 Ok(())
111 }
112}