Skip to main content

rusty_rich/
logging.rs

1//! Logging integration — equivalent to Rich's `logging.py`.
2//!
3//! Provides a log handler that renders log records with Rich formatting.
4
5use std::io::Write;
6
7use crate::console::Console;
8use crate::highlighter::ReprHighlighter;
9use crate::style::Style;
10use crate::text::Text;
11
12/// A handler that renders Python-style log records with Rich formatting.
13///
14/// In Rust, this integrates with the `log` crate.
15pub struct RichHandler {
16    pub console: Console,
17    pub show_time: bool,
18    pub show_level: bool,
19    pub show_path: bool,
20    pub enable_link_path: bool,
21    pub markup: bool,
22    pub highlighter: ReprHighlighter,
23}
24
25impl RichHandler {
26    pub fn new() -> Self {
27        Self {
28            console: Console::new(),
29            show_time: true,
30            show_level: true,
31            show_path: true,
32            enable_link_path: false,
33            markup: false,
34            highlighter: ReprHighlighter::new(),
35        }
36    }
37
38    /// Render a single log record.
39    pub fn render(
40        &self,
41        level: log::Level,
42        message: &str,
43        _module_path: Option<&str>,
44        file: Option<&str>,
45        line: Option<u32>,
46    ) -> String {
47        let mut text = Text::new("");
48
49        if self.show_time {
50            let now = chrono::Local::now();
51            let time_str = format!("[{}]", now.format("%H:%M:%S"));
52            text.append_styled(time_str, Style::new().dim(true));
53            text.append_styled(" ", Style::new());
54        }
55
56        if self.show_level {
57            let level_style = match level {
58                log::Level::Error => Style::new().color(crate::color::Color::parse("red").unwrap()).bold(true),
59                log::Level::Warn => Style::new().color(crate::color::Color::parse("yellow").unwrap()),
60                log::Level::Info => Style::new().color(crate::color::Color::parse("green").unwrap()),
61                log::Level::Debug => Style::new().color(crate::color::Color::parse("blue").unwrap()),
62                log::Level::Trace => Style::new().color(crate::color::Color::parse("bright_black").unwrap()),
63            };
64            text.append_styled(format!("{level:<5}"), level_style);
65            text.append_styled(" ", Style::new());
66        }
67
68        // Message
69        text.append_styled(message, Style::new());
70
71        // File location
72        if self.show_path {
73            if let (Some(file), Some(line)) = (file, line) {
74                text.append_styled(" ", Style::new());
75                let location = format!("{file}:{line}");
76                text.append_styled(format!("[{location}]"), Style::new().dim(true).italic(true));
77            }
78        }
79
80        text.render()
81    }
82
83    /// Emit a log record (integrates with the `log` crate).
84    pub fn emit(&mut self, record: &log::Record) {
85        let formatted = self.render(
86            record.level(),
87            record.args().to_string().as_str(),
88            record.module_path(),
89            record.file(),
90            record.line(),
91        );
92        let _ = writeln!(self.console.file, "{formatted}");
93        let _ = self.console.file.flush();
94    }
95}
96
97impl Default for RichHandler {
98    fn default() -> Self {
99        Self::new()
100    }
101}
102
103/// Convenience: install a Rich logger.
104pub fn install() -> Result<(), log::SetLoggerError> {
105    // This requires a static/global logger; for simplicity, we'll just
106    // provide the handler for manual use.
107    Ok(())
108}
109
110/// Style a log level name.
111pub fn style_level(level: log::Level) -> Style {
112    match level {
113        log::Level::Error => Style::new()
114            .color(crate::color::Color::parse("red").unwrap())
115            .bold(true),
116        log::Level::Warn => Style::new()
117            .color(crate::color::Color::parse("yellow").unwrap()),
118        log::Level::Info => Style::new()
119            .color(crate::color::Color::parse("green").unwrap()),
120        log::Level::Debug => Style::new()
121            .color(crate::color::Color::parse("blue").unwrap()),
122        log::Level::Trace => Style::new()
123            .color(crate::color::Color::parse("bright_black").unwrap()),
124    }
125}