1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use log::*;
use std::fmt::Write;
use stdweb::js;
struct Logger {
filter: LevelFilter,
format: Box<dyn Fn(&mut String, &Record) -> std::fmt::Result + Send + Sync + 'static>,
}
impl Logger {
fn new() -> Self {
Self {
filter: LevelFilter::Trace,
format: Box::new(|s, r| write!(s, "{}: {}", r.level(), r.args())),
}
}
}
pub struct Builder {
logger: Logger,
}
impl Builder {
fn new() -> Self {
Self {
logger: Logger::new(),
}
}
pub fn format(
mut self,
fmt: impl Fn(&mut String, &Record) -> std::fmt::Result + Send + Sync + 'static,
) -> Self {
self.logger.format = Box::new(fmt);
self
}
pub fn filter(mut self, filter: LevelFilter) -> Self {
self.logger.filter = filter;
self
}
pub fn detail(mut self) -> Self {
self.logger.format = Box::new(|s, r| {
write!(
s,
"{}: {} ({}({}))",
r.level(),
r.args(),
r.file().unwrap_or("<unknown>"),
r.line().unwrap_or(0),
)
});
self
}
pub fn build(self) {
let level = self.logger.filter.clone();
if set_boxed_logger(Box::new(self.logger)).is_ok() {
set_max_level(level);
}
}
}
impl log::Log for Logger {
fn enabled(&self, m: &Metadata) -> bool {
match self.filter.to_level() {
Some(level) => m.level() <= level,
None => false,
}
}
fn log(&self, record: &Record) {
let mut s = String::new();
if let Err(e) = (self.format)(&mut s, record) {
js! { @(no_return) console.error(@{e.to_string()}); }
} else {
match record.level() {
Level::Error => js! { @(no_return) console.error(@{s}); },
Level::Warn => js! { @(no_return) console.warn(@{s}); },
Level::Info => js! { @(no_return) console.info(@{s}); },
Level::Debug => js! { @(no_return) console.debug(@{s}); },
Level::Trace => js! { @(no_return) console.trace(@{s}); },
}
}
}
fn flush(&self) {}
}
pub fn init() {
builder().build()
}
pub fn builder() -> Builder {
Builder::new()
}
pub fn init_with_level(level: Level) {
builder().filter(level.to_level_filter()).build()
}