extlog/
loglib.rs

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};
19//use std::collections::HashMap;
20use 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}