tui_logger/logger/
api.rs

1use std::thread;
2
3use crate::CircularBuffer;
4use crate::TuiLoggerFile;
5use log::LevelFilter;
6use log::Record;
7use log::SetLoggerError;
8
9use crate::TUI_LOGGER;
10
11// Lots of boilerplate code, so that init_logger can return two error types...
12#[derive(Debug)]
13pub enum TuiLoggerError {
14    SetLoggerError(SetLoggerError),
15    ThreadError(std::io::Error),
16}
17impl std::error::Error for TuiLoggerError {
18    fn description(&self) -> &str {
19        match self {
20            TuiLoggerError::SetLoggerError(_) => "SetLoggerError",
21            TuiLoggerError::ThreadError(_) => "ThreadError",
22        }
23    }
24    fn cause(&self) -> Option<&dyn std::error::Error> {
25        match self {
26            TuiLoggerError::SetLoggerError(_) => None,
27            TuiLoggerError::ThreadError(err) => Some(err),
28        }
29    }
30}
31impl std::fmt::Display for TuiLoggerError {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        match self {
34            TuiLoggerError::SetLoggerError(err) => write!(f, "SetLoggerError({})", err),
35            TuiLoggerError::ThreadError(err) => write!(f, "ThreadError({})", err),
36        }
37    }
38}
39
40/// Init the logger.
41pub fn init_logger(max_level: LevelFilter) -> Result<(), TuiLoggerError> {
42    let join_handle = thread::Builder::new()
43        .name("tui-logger::move_events".into())
44        .spawn(|| {
45            let duration = std::time::Duration::from_millis(10);
46            loop {
47                thread::park_timeout(duration);
48                TUI_LOGGER.move_events();
49            }
50        })
51        .map_err(|err| TuiLoggerError::ThreadError(err))?;
52    TUI_LOGGER.hot_log.lock().mover_thread = Some(join_handle);
53    if cfg!(feature = "tracing-support") {
54        set_default_level(max_level);
55        Ok(())
56    } else {
57        log::set_max_level(max_level);
58        log::set_logger(&*TUI_LOGGER).map_err(|err| TuiLoggerError::SetLoggerError(err))
59    }
60}
61
62/// Set the depth of the hot buffer in order to avoid message loss.
63/// This is effective only after a call to move_events()
64pub fn set_hot_buffer_depth(depth: usize) {
65    TUI_LOGGER.inner.lock().hot_depth = depth;
66}
67
68/// Set the depth of the circular buffer in order to avoid message loss.
69/// This will delete all existing messages in the circular buffer.
70pub fn set_buffer_depth(depth: usize) {
71    TUI_LOGGER.inner.lock().events = CircularBuffer::new(depth);
72}
73
74/// Define filename and log formmating options for file dumping.
75pub fn set_log_file(file_options: TuiLoggerFile) {
76    TUI_LOGGER.inner.lock().dump = Some(file_options);
77}
78
79/// Set default levelfilter for unknown targets of the logger
80pub fn set_default_level(levelfilter: LevelFilter) {
81    TUI_LOGGER.hot_select.lock().default = levelfilter;
82    TUI_LOGGER.inner.lock().default = levelfilter;
83}
84
85/// Remove env filter - for debugging purposes
86pub fn remove_env_filter() {
87    TUI_LOGGER.hot_select.lock().filter = None;
88    TUI_LOGGER.inner.lock().filter = None;
89}
90
91fn set_env_filter(filter1: env_filter::Filter, filter2: env_filter::Filter) {
92    // Filter does not support Copy. In order to not unnecessary lock hot_select,
93    // we use a manual copy of the env filter.
94    TUI_LOGGER.hot_select.lock().filter = Some(filter1);
95    TUI_LOGGER.inner.lock().filter = Some(filter2);
96}
97
98/// Parse environment variable for env_filter
99pub fn set_env_filter_from_string(filterstring: &str) {
100    let mut builder1 = env_filter::Builder::new();
101    let mut builder2 = env_filter::Builder::new();
102
103    builder1.parse(filterstring);
104    builder2.parse(filterstring);
105
106    set_env_filter(builder1.build(), builder2.build());
107}
108
109/// Parse environment variable for env_filter
110pub fn set_env_filter_from_env(env_name: Option<&str>) {
111    let mut builder1 = env_filter::Builder::new();
112    let mut builder2 = env_filter::Builder::new();
113
114    // Parse a directives string from an environment variable
115    if let Ok(ref filter) = std::env::var(env_name.unwrap_or("RUST_LOG")) {
116        builder1.parse(filter);
117        builder2.parse(filter);
118
119        set_env_filter(builder1.build(), builder2.build());
120    }
121}
122
123/// Set levelfilter for a specific target in the logger
124pub fn set_level_for_target(target: &str, levelfilter: LevelFilter) {
125    let h = fxhash::hash64(&target);
126    TUI_LOGGER.inner.lock().targets.set(target, levelfilter);
127    let mut hs = TUI_LOGGER.hot_select.lock();
128    hs.hashtable.insert(h, levelfilter);
129}
130
131// Move events from the hot log to the main log
132pub fn move_events() {
133    TUI_LOGGER.move_events();
134}
135
136/// A simple `Drain` to log any event directly.
137#[derive(Default)]
138pub struct Drain;
139
140impl Drain {
141    /// Create a new Drain
142    pub fn new() -> Self {
143        Drain
144    }
145    /// Log the given record to the main tui-logger
146    pub fn log(&self, record: &Record) {
147        TUI_LOGGER.raw_log(record)
148    }
149}