1use std::io::Write;
6
7use crate::console::Console;
8use crate::highlighter::ReprHighlighter;
9use crate::style::Style;
10use crate::text::Text;
11
12pub 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 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 text.append_styled(message, Style::new());
70
71 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 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
103pub fn install() -> Result<(), log::SetLoggerError> {
105 Ok(())
108}
109
110pub 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}