tui_logger/logger/
api.rs

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