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