1
2
3#[cfg(target_os = "windows")]
4use crate::loglib_windows::{win_output_debug};
5use log::{LevelFilter};
6use log::{error, info, trace,warn,debug};
7use log4rs::append::console::{ConsoleAppender, Target};
8use log4rs::append::file::FileAppender;
9use log4rs::config::{Appender, Config, Root,RootBuilder,ConfigBuilder};
10use log4rs::encode::pattern::PatternEncoder;
11use log4rs::filter::threshold::ThresholdFilter;
12use log4rs::append::rolling_file::RollingFileAppender;
13use log4rs::append::rolling_file::policy::compound::CompoundPolicy;
14use log4rs::append::rolling_file::policy::compound::trigger::size::SizeTrigger;
15use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller;
16use std::error::Error;
17use std::boxed::Box;
18use chrono::{Local,Datelike,Timelike};
19use lazy_static::lazy_static;
21
22use std::sync::{Mutex,Arc};
23
24
25
26const DEFAULT_MSG_FMT :&str = "{m}";
27
28lazy_static! {
29 static ref LOGGER_LEVEL :Arc<Mutex<i64>> = Arc::new(Mutex::new(0 as i64));
30}
31
32fn get_logger_level() -> i64 {
33 let scb = LOGGER_LEVEL.lock().unwrap();
34 let retv :i64;
35 retv = *scb;
36 return retv;
37}
38
39fn set_logger_level(nv :i64) -> i64 {
40 let mut scb = LOGGER_LEVEL.lock().unwrap();
41 let retv :i64;
42
43 retv = *scb;
44 *scb = nv;
45 return retv;
46}
47
48fn parse_log_var(s :&str) -> (String,u64,u32) {
49 let sarr :Vec<&str> = s.split(",").collect();
50 let fname :String;
51 let mut fsize :u64 = 0;
52 let mut times :u32 = 0;
53 if sarr.len() > 1 {
54 fname = format!("{}",sarr[0]);
55 let bss :String = format!("{}",sarr[1]);
56 let bs2 = &bss;
57 let bs = bs2.as_bytes();
58 let mut number :String = "".to_string();
59 let mut unit :String = "".to_string();
60 let mut n :usize = bs.len();
61 match bs2.find(|c :char| !c.is_digit(10)) {
62 Some(vn) => {n = vn},
63 None => {},
64 }
65 let mut idx :usize = 0 ;
66 while idx < n {
67 number.push(bs[idx] as char);
68 idx += 1;
69 }
70
71 while idx < bs.len() {
72 unit.push(bs[idx] as char);
73 idx += 1;
74 }
75
76
77 match number.parse::<u64>() {
78 Ok(n) => {fsize = n},
79 Err(_e) => {},
80 }
81 if unit == "b" || unit == "B" {
82 fsize = fsize;
83 } else if unit == "k" || unit == "K" {
84 fsize *= 1024;
85 } else if unit == "m" || unit == "M" {
86 fsize *= 1024 * 1024;
87 } else if unit == "g" || unit == "G" {
88 fsize *= 1024 * 1024 * 1024;
89 } else if unit == "t" || unit == "T" {
90 fsize *= 1024 * 1024 * 1024 * 1024;
91 }
92
93 if sarr.len() > 2 {
94 let tstr:String = format!("{}",sarr[2]);
95 match tstr.parse::<u32>() {
96 Ok(n) => {times = n},
97 Err(_e) => {},
98 }
99 }
100
101 } else {
102 fname = format!("{}",s);
103 }
104 return (fname,fsize,times);
105}
106
107pub struct ExtLogVar {
108 pub lognostderr : bool,
109 pub logfiles :Vec<String>,
110 pub logapps :Vec<String>,
111 pub logverbose :i64,
112}
113
114impl Default for ExtLogVar {
115 fn default() -> Self {
116 Self {
117 lognostderr : false,
118 logfiles : Vec::new(),
119 logapps : Vec::new(),
120 logverbose : 0,
121 }
122 }
123}
124
125
126pub fn ext_init_log(ns :&ExtLogVar) -> Result<(),Box<dyn Error>> {
127 let level :LevelFilter;
128 let mut rbuiler :RootBuilder;
129 let mut cbuild :ConfigBuilder;
130 let mut sarr :Vec<String>;
131 let retv :i64;
132 let nostderr :bool;
133 let stderr =ConsoleAppender::builder().encoder(Box::new(PatternEncoder::new(DEFAULT_MSG_FMT))).target(Target::Stderr).build();
134
135 retv = ns.logverbose;
136
137 if retv >= 4 {
138 level = log::LevelFilter::Trace;
139 } else if retv >= 3 {
140 level = log::LevelFilter::Debug;
141 } else if retv >= 2 {
142 level = log::LevelFilter::Info;
143 } else if retv >= 1 {
144 level = log::LevelFilter::Warn;
145 } else {
146 level = log::LevelFilter::Error;
147 }
148
149 set_logger_level(retv);
150
151 cbuild = Config::builder();
152 rbuiler = Root::builder();
153 nostderr = ns.lognostderr;
154
155
156 if !nostderr {
157 cbuild = cbuild.appender(
158 Appender::builder()
159 .filter(Box::new(ThresholdFilter::new(level)))
160 .build("stderr", Box::new(stderr)),
161 );
162 rbuiler = rbuiler.appender("stderr");
163 }
164
165
166 sarr = ns.logfiles.clone();
167 for wf in sarr.iter() {
168 let (fname,fsize,times) = parse_log_var(wf);
169 if fsize == 0 {
170 let logfile = FileAppender::builder().append(false).encoder(Box::new(PatternEncoder::new(DEFAULT_MSG_FMT))).build(&fname)?;
171 cbuild = cbuild.appender(Appender::builder().build(&fname, Box::new(logfile)));
172 rbuiler = rbuiler.appender(&fname);
173 } else {
174 let fpattern = format!("{}.{{}}.gz",fname);
175 let mut tfiles :u32 = 1;
176 if times > 0 {
177 tfiles = times;
178 }
179 let logfile = RollingFileAppender::builder().append(false).encoder(Box::new(PatternEncoder::new(DEFAULT_MSG_FMT))).build(&fname,
180 Box::new(CompoundPolicy::new(
181 Box::new(SizeTrigger::new(fsize)),
182 Box::new(FixedWindowRoller::builder().build(&fpattern,tfiles).unwrap())
183 )))?;
184 cbuild = cbuild.appender(Appender::builder().build(&fname, Box::new(logfile)));
185 rbuiler = rbuiler.appender(&fname);
186 }
187 }
188
189
190 sarr = ns.logapps.clone();
191 for wf in sarr.iter() {
192 let (fname,fsize,times) = parse_log_var(wf);
193 if fsize == 0 {
194 let logfile = FileAppender::builder().append(true).encoder(Box::new(PatternEncoder::new(DEFAULT_MSG_FMT))).build(wf)?;
195 cbuild = cbuild.appender(Appender::builder().build(wf, Box::new(logfile)));
196 rbuiler = rbuiler.appender(wf);
197 } else {
198 let fpattern = format!("{}.{{}}.gz",fname);
199 let mut tfiles :u32 = 1;
200 if times > 0 {
201 tfiles = times;
202 }
203 let logfile = RollingFileAppender::builder().append(true).encoder(Box::new(PatternEncoder::new(DEFAULT_MSG_FMT))).build(&fname,
204 Box::new(CompoundPolicy::new(
205 Box::new(SizeTrigger::new(fsize)),
206 Box::new(FixedWindowRoller::builder().build(&fpattern,tfiles).unwrap())
207 )))?;
208 cbuild = cbuild.appender(Appender::builder().build(&fname, Box::new(logfile)));
209 rbuiler = rbuiler.appender(&fname);
210 }
211 }
212
213
214 let config = cbuild.build(rbuiler.build(level))?;
215 let _ = log4rs::init_config(config)?;
216
217 Ok(())
218}
219
220
221
222pub fn log_get_timestamp() -> String {
223 let now = Local::now();
224 return format!("{}/{}/{} {}:{}:{}",now.year(),now.month(),now.day(),now.hour(),now.minute(),now.second());
225}
226
227#[cfg(target_os = "windows")]
228fn log_output_function_inner(level :i64, outs :&str) {
229 if level <= get_logger_level() {
230 if level == 0 {
231 error!("{}",outs);
232 } else if level == 1 {
233 warn!("{}",outs);
234 } else if level == 2 {
235 info!("{}",outs);
236 } else if level == 3 {
237 debug!("{}",outs);
238 } else if level >= 4 {
239 trace!("{}",outs);
240 }
241 win_output_debug(outs);
242 }
243 return;
244}
245
246#[cfg(not(target_os = "windows"))]
247fn log_output_function_inner(level :i64, outs :&str) {
248 if level <= get_logger_level() {
249 if level == 0 {
250 error!("{}",outs);
251 } else if level == 1 {
252 warn!("{}",outs);
253 } else if level == 2 {
254 info!("{}",outs);
255 } else if level == 3 {
256 debug!("{}",outs);
257 } else if level >= 4 {
258 trace!("{}",outs);
259 }
260 }
261 return;
262}
263
264
265pub fn log_output_function(level :i64, outs :&str) {
266 return log_output_function_inner(level,outs);
267}
268
269#[macro_export]
270macro_rules! format_str_log {
271 ($info:tt,$iv:expr,$($arg:tt)+) => {
272 let mut c:String;
273 #[cfg(feature="longname_mode")]
274 {
275 c = format!("[{}:{}]",file!(),line!());
276 }
277 #[cfg(not(feature="longname_mode"))]
278 {
279 let path = std::path::Path::new(file!());
280 let ext = path.extension();
281 let mname = path.file_stem();
282 if ext.is_some() && mname.is_some() {
283 c = format!("[{}.{}:{}]",mname.unwrap().to_string_lossy(),ext.unwrap().to_string_lossy(),line!());
284 } else {
285 c = format!("[{}:{}]",mname.unwrap().to_string_lossy(),line!());
286 }
287 }
288 c.push_str(&format!("{} ",$info));
289 c.push_str(&log_get_timestamp());
290 c.push_str(": ");
291 c.push_str(&(format!($($arg)+)[..]));
292 c.push_str("\n");
293 log_output_function($iv, &c);
294 }
295}
296
297#[macro_export]
298macro_rules! debug_error {
299 ($($arg:tt)+) => {
300 format_str_log!("<ERROR>",0,$($arg)+);
301 }
302}
303
304#[macro_export]
305macro_rules! debug_warn {
306 ($($arg:tt)+) => {
307 format_str_log!("<WARN>",1,$($arg)+);
308 }
309}
310
311
312#[macro_export]
313macro_rules! debug_info {
314 ($($arg:tt)+) => {
315 format_str_log!("<INFO>",2,$($arg)+);
316 }
317}
318
319#[macro_export]
320macro_rules! debug_debug {
321 ($($arg:tt)+) => {
322 format_str_log!("<DEBUG>",3,$($arg)+);
323 }
324}
325
326
327#[macro_export]
328macro_rules! debug_trace {
329 ($($arg:tt)+) => {
330 format_str_log!("<TRACE>",4,$($arg)+);
331 }
332}
333
334#[macro_export]
335macro_rules! format_buffer_log {
336 ($buf:expr,$len:expr,$info:tt,$iv:expr,$($arg:tt)+) => {
337 let mut c:String;
338 #[cfg(feature="longname_mode")]
339 {
340 c = format!("[{}:{}]",file!(),line!());
341 }
342 #[cfg(not(feature="longname_mode"))]
343 {
344 let path = std::path::Path::new(file!());
345 let ext = path.extension();
346 let mname = path.file_stem();
347 if ext.is_some() && mname.is_some() {
348 c = format!("[{}.{}:{}]",mname.unwrap().to_string_lossy(),ext.unwrap().to_string_lossy(),line!());
349 } else {
350 c = format!("[{}:{}]",mname.unwrap().to_string_lossy(),line!());
351 }
352 }
353 c.push_str(&format!("{} ",$info));
354 c.push_str(&log_get_timestamp());
355 c.push_str(": ");
356 c.push_str(&(format!($($arg)+)[..]));
357 let _ptr :*const u8 = $buf as *const u8;
358 let mut _ci :usize;
359 let _totallen: usize = $len as usize;
360 let mut _lasti :usize = 0;
361 let mut _nb :u8;
362 c.push_str(&format!(" buffer [{:?}][{}:0x{:x}]",_ptr,_totallen,_totallen));
363 _ci = 0;
364 while _ci < _totallen {
365 if (_ci % 16) == 0 {
366 if _ci > 0 {
367 c.push_str(" ");
368 while _lasti < _ci {
369 unsafe{
370 _nb = *_ptr.offset(_lasti as isize);
371 }
372
373 if _nb >= 0x20 && _nb <= 0x7e {
374 c.push(_nb as char);
375 } else {
376 c.push_str(".");
377 }
378 _lasti += 1;
379 }
380 }
381 c.push_str(&format!("\n0x{:08x}:", _ci));
382 }
383 unsafe {_nb = *_ptr.offset(_ci as isize);}
384 c.push_str(&format!(" 0x{:02x}",_nb));
385 _ci += 1;
386 }
387
388 if _lasti < _ci {
389 while (_ci % 16) != 0 {
390 c.push_str(" ");
391 _ci += 1;
392 }
393
394 c.push_str(" ");
395
396 while _lasti < _totallen {
397 unsafe {_nb = *_ptr.offset(_lasti as isize);}
398 if _nb >= 0x20 && _nb <= 0x7e {
399 c.push(_nb as char);
400 } else {
401 c.push_str(".");
402 }
403 _lasti += 1;
404 }
405 }
406 c.push_str("\n");
407 log_output_function($iv,&c);
408 }
409}
410
411#[macro_export]
412macro_rules! debug_buffer_error {
413 ($buf:expr,$len:expr,$($arg:tt)+) => {
414 format_buffer_log!($buf,$len,"<ERROR>",0,$($arg)+);
415 }
416}
417
418#[macro_export]
419macro_rules! debug_buffer_warn {
420 ($buf:expr,$len:expr,$($arg:tt)+) => {
421 format_buffer_log!($buf,$len,"<WARN>",1,$($arg)+);
422 }
423}
424
425#[macro_export]
426macro_rules! debug_buffer_info {
427 ($buf:expr,$len:expr,$($arg:tt)+) => {
428 format_buffer_log!($buf,$len,"<INFO>",2,$($arg)+);
429 }
430}
431
432#[macro_export]
433macro_rules! debug_buffer_debug {
434 ($buf:expr,$len:expr,$($arg:tt)+) => {
435 format_buffer_log!($buf,$len,"<DEBUG>",3,$($arg)+);
436 }
437}
438
439#[macro_export]
440macro_rules! debug_buffer_trace {
441 ($buf:expr,$len:expr,$($arg:tt)+) => {
442 format_buffer_log!($buf,$len,"<TRACE>",4,$($arg)+);
443 }
444}