1#![allow(dead_code, unused_imports)]
2
3mod utils;
4
5use utils::{format_path};
6use log::{Level, Log, Metadata, Record, SetLoggerError};
7
8pub use utils::{Timezone};
9pub use log::{LevelFilter};
10
11
12cfg_if::cfg_if! {
13 if #[cfg(target_arch = "wasm32")]
14 {
15 use web_sys::console;
16 use wasm_bindgen::{JsValue};
17 } else {
18 use utils::{format_time};
19 use ansi_term::Color;
20 }
21}
22
23#[cfg(not(target_arch = "wasm32"))]
24static LOG_LEVEL_NAMES: [&str; 6] = ["N/A", "E", "W", "I", "D", "T"];
25
26#[cfg(not(target_arch = "wasm32"))]
27fn level_to_str(l: &Level) -> &'static str {
28 LOG_LEVEL_NAMES[*l as usize]
29}
30
31
32#[derive(Clone)]
33pub struct Options {
34 pub level: LevelFilter,
35 pub print_level: bool,
36 pub timezone: Timezone,
37 pub colored: bool,
38 pub mods: Vec<String>,
39}
40
41impl Default for Options {
42 fn default() -> Self {
43 Self {
44 level: LevelFilter::Trace,
45 print_level: true,
46 timezone: Timezone::Local,
47 colored: true,
48 mods: vec![],
49 }
50 }
51}
52
53pub struct XLog {
54 level: LevelFilter,
55 print_level: bool,
56 timezone: Timezone,
57 colored: bool,
58 mods: Vec<String>,
59}
60
61impl XLog {
62 #[must_use = "You must call init() to begin logging"]
63 pub fn new(opts: Options) -> XLog {
64 let Options {
65 level, print_level, timezone, colored, mods
66 } = opts;
67 XLog {
68 level,
69 print_level,
70 timezone,
71 colored,
72 mods,
73 }
74 }
75
76 pub fn init(self) -> Result<(), SetLoggerError> {
77 log::set_max_level(log::STATIC_MAX_LEVEL);
78 log::set_boxed_logger(Box::new(self))?;
79 Ok(())
80 }
81}
82
83impl Default for XLog {
84 fn default() -> Self {
85 XLog::new(Options::default())
86 }
87}
88
89impl Log for XLog {
90 fn enabled(&self, metadata: &Metadata) -> bool {
91 let target = metadata.target().to_string();
92 let mods: Vec<&str> = target.split("::").collect();
93
94 if self.mods.is_empty() == false {
95 let finds: Vec<&String> = self.mods.iter().filter_map(|x| {
96 if *x == mods[0].to_string() {
97 Some(x)
98 } else {
99 None
100 }
101 }).collect();
102 if finds.is_empty() {
103 return false;
104 }
105 }
106
107 metadata.level().to_level_filter() <= self.level
108 }
109
110 fn log(&self, record: &Record) {
111 if self.enabled(record.metadata()) {
112 let pathname = format_path(record.file().unwrap_or("???"),
113 record.line().unwrap_or(0));
114
115
116 #[cfg(target_arch = "wasm32")]
117 {
118 let level = match self.print_level {
119 true => format!("{}", &record.level().as_str()),
120 false => "".to_string()
121 };
122 let msg = format!("{}", record.args());
123 let level_pre = match record.level() {
124 Level::Trace => "color: white; background: #747474",
125 Level::Debug => "color: white; background: #2330da",
126 Level::Info => "color: white; background: #00831c",
127 Level::Warn => "color: white; background: #e17400",
128 Level::Error => "color: white; background: #b90008",
129 };
130 let console_log = match record.level() {
131 Level::Trace => console::debug_4,
132 Level::Debug => console::log_4,
133 Level::Info => console::info_4,
134 Level::Warn => console::warn_4,
135 Level::Error => console::error_4,
136 };
137 let msg_pre = "color: inherit";
145
146 console_log(
147 &JsValue::from(format!("%c{}%c {} %c{}",
148 level, pathname, msg
149 )),
150 &JsValue::from(level_pre),
151 &JsValue::from("color: inherit"),
152 &JsValue::from(msg_pre),
153 );
154 }
155
156 #[cfg(not(target_arch = "wasm32"))]
157 {
158 let timestamp = format_time(&self.timezone);
159
160 let level = match self.print_level {
161 true => format!("[{}] ", level_to_str(&record.level())),
162 false => "".to_string()
163 };
164
165 let mut msg = format!("{}{}", level, record.args());
166
167 let mut pathname = pathname;
168 if self.colored {
169 pathname = Color::Blue.paint(pathname.as_str()).to_string();
172
173 msg = match record.level() {
174 Level::Trace => Color::White.paint(msg).to_string(),
175 Level::Debug => Color::Blue.paint(msg).to_string(),
176 Level::Info => Color::Green.paint(msg).to_string(),
177 Level::Warn => Color::Yellow.paint(msg).to_string(),
178 Level::Error => Color::Red.paint(msg).to_string(),
179 };
180 }
181
182 let message = format!("{}{} {}", timestamp, pathname, msg);
183
184 #[cfg(not(feature = "stderr"))]
185 println!("{}", message);
186 }
187
188
189 #[cfg(feature = "stderr")]
190 eprintln!("{}", message);
191 }
192 }
193
194 fn flush(&self) {}
195}
196
197use std::sync::Once;
198
199static INIT: Once = Once::new();
200
201pub fn init_once(opts: Option<Options>) {
202 INIT.call_once(|| {
203 let opts = opts.unwrap_or_default();
204 XLog::new(opts).init().unwrap();
205 });
207}
208
209pub extern crate log;
210
211#[macro_export]
214macro_rules! trace {
215 ($($arg:tt)*) => ({
219 x_log::init_once(None);
220 $crate::log::log!(log::Level::Trace, $($arg)+);
221 });
222}
223
224#[macro_export]
225macro_rules! debug {
226 ($($arg:tt)*) => ({
227 x_log::init_once(None);
228 $crate::log::log!(log::Level::Debug, $($arg)+);
229 });
230}
231
232#[macro_export]
233macro_rules! info {
234 ($($arg:tt)*) => ({
235 x_log::init_once(None);
236 $crate::log::log!(log::Level::Info, $($arg)+);
237 });
238}
239
240#[macro_export]
241macro_rules! warn {
242 ($($arg:tt)*) => ({
243 x_log::init_once(None);
244 $crate::log::log!(log::Level::Warn, $($arg)+);
245 });
246}
247
248#[macro_export]
249macro_rules! error {
250 ($($arg:tt)*) => ({
251 x_log::init_once(None);
252 $crate::log::log!(log::Level::Error, $($arg)+);
253 });
254}
255#[doc(hidden)]
257pub use utils::__print_val;
258
259#[macro_export]
260macro_rules! __val {
261 ($fmt:expr, $($arg:tt)+) => (
262 x_log::__print_val(file!(), line!(), format_args!($fmt, $($arg)+));
263 )
264}
265
266#[macro_export]
268macro_rules! val {
269 ($v:expr) => {
270 __val!("\n{}︎︎︎︎⏤►{:?}", stringify!($v), $v);
271 };
272 ($v:expr, $v2:expr) => {
273 __val!("\n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?}", stringify!($v), $v, stringify!($v2), $v2,);
274 };
275 ($v:expr, $v2:expr, $v3:expr) => {
276 __val!("\n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3);
277 };
278 ($v:expr, $v2:expr, $v3:expr, $v4:expr) => {
279 __val!("\n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3, stringify!($v4), $v4);
280 };
281 ($v:expr, $v2:expr, $v3:expr, $v4:expr, $v5:expr) => {
282 __val!("\n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3, stringify!($v4), $v4, stringify!($v5), $v5);
283 };
284 ($v:expr, $v2:expr, $v3:expr, $v4:expr, $v5:expr, $v6:expr) => {
285 __val!("\n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?} \n{}︎︎︎︎⏤►{:?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3, stringify!($v4), $v4, stringify!($v5), $v5, stringify!($v6), $v6);
286 };
287}
288
289#[macro_export]
291macro_rules! valf {
292 ($v:expr) => {
293 __val!("\n{}︎︎︎︎⏤►{:#?}", stringify!($v), $v);
294 };
295 ($v:expr, $v2:expr) => {
296 __val!("\n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?}", stringify!($v), $v, stringify!($v2), $v2,);
297 };
298 ($v:expr, $v2:expr, $v3:expr) => {
299 __val!("\n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3);
300 };
301 ($v:expr, $v2:expr, $v3:expr, $v4:expr) => {
302 __val!("\n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3, stringify!($v4), $v4);
303 };
304 ($v:expr, $v2:expr, $v3:expr, $v4:expr, $v5:expr) => {
305 __val!("\n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3, stringify!($v4), $v4, stringify!($v5), $v5);
306 };
307 ($v:expr, $v2:expr, $v3:expr, $v4:expr, $v5:expr, $v6:expr) => {
308 __val!("\n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?} \n{}︎︎︎︎⏤►{:#?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3, stringify!($v4), $v4, stringify!($v5), $v5, stringify!($v6), $v6);
309 };
310}
311#[macro_export]
334macro_rules! valn {
335 ($v:expr) => {
336 __val!("{}︎︎︎︎⏤►{:?}", stringify!($v), $v);
337 };
338 ($v:expr, $v2:expr) => {
339 __val!("{}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}", stringify!($v), $v, stringify!($v2), $v2,);
340 };
341 ($v:expr, $v2:expr, $v3:expr) => {
342 __val!("{}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3);
343 };
344 ($v:expr, $v2:expr, $v3:expr, $v4:expr) => {
345 __val!("{}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3, stringify!($v4), $v4);
346 };
347 ($v:expr, $v2:expr, $v3:expr, $v4:expr, $v5:expr) => {
348 __val!("{}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3, stringify!($v4), $v4, stringify!($v5), $v5);
349 };
350 ($v:expr, $v2:expr, $v3:expr, $v4:expr, $v5:expr, $v6:expr) => {
351 __val!("{}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}, {}︎︎︎︎⏤►{:?}", stringify!($v), $v, stringify!($v2), $v2, stringify!($v3), $v3, stringify!($v4), $v4, stringify!($v5), $v5, stringify!($v6), $v6);
352 };
353}