]> git.lizzy.rs Git - rust.git/blob - crates/rust-analyzer/src/bin/logger.rs
14887c5ccfefb10132fe2a8ce4a50e667c3edf44
[rust.git] / crates / rust-analyzer / src / bin / logger.rs
1 //! Simple logger that logs either to stderr or to a file, using `env_logger`
2 //! filter syntax. Amusingly, there's no crates.io crate that can do this and
3 //! only this.
4
5 use std::{
6     fs::File,
7     io::{self, BufWriter, Write},
8 };
9
10 use env_logger::filter::{Builder, Filter};
11 use log::{Log, Metadata, Record};
12 use parking_lot::Mutex;
13
14 pub(crate) struct Logger {
15     filter: Filter,
16     file: Option<Mutex<BufWriter<File>>>,
17     no_buffering: bool,
18 }
19
20 impl Logger {
21     pub(crate) fn new(log_file: Option<File>, no_buffering: bool, filter: Option<&str>) -> Logger {
22         let filter = {
23             let mut builder = Builder::new();
24             if let Some(filter) = filter {
25                 builder.parse(filter);
26             }
27             builder.build()
28         };
29
30         let file = log_file.map(|it| Mutex::new(BufWriter::new(it)));
31
32         Logger { filter, file, no_buffering }
33     }
34
35     pub(crate) fn install(self) {
36         let max_level = self.filter.filter();
37         let _ = log::set_boxed_logger(Box::new(self)).map(|()| log::set_max_level(max_level));
38     }
39 }
40
41 impl Log for Logger {
42     fn enabled(&self, metadata: &Metadata) -> bool {
43         self.filter.enabled(metadata)
44     }
45
46     fn log(&self, record: &Record) {
47         if !self.filter.matches(record) {
48             return;
49         }
50
51         let should_flush = match &self.file {
52             Some(w) => {
53                 let _ = writeln!(
54                     w.lock(),
55                     "[{} {}] {}",
56                     record.level(),
57                     record.module_path().unwrap_or_default(),
58                     record.args(),
59                 );
60                 self.no_buffering
61             }
62             None => {
63                 eprintln!(
64                     "[{} {}] {}",
65                     record.level(),
66                     record.module_path().unwrap_or_default(),
67                     record.args(),
68                 );
69                 true // flush stderr unconditionally
70             }
71         };
72
73         if should_flush {
74             self.flush();
75         }
76     }
77
78     fn flush(&self) {
79         match &self.file {
80             Some(w) => {
81                 let _ = w.lock().flush();
82             }
83             None => {
84                 let _ = io::stderr().flush();
85             }
86         }
87     }
88 }