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 {
28 Self {
29 console: Console::new(),
30 show_time: true,
31 show_level: true,
32 show_path: true,
33 enable_link_path: false,
34 markup: false,
35 highlighter: ReprHighlighter::new(),
36 }
37 }
38
39 pub fn render(
41 &self,
42 level: log::Level,
43 message: &str,
44 _module_path: Option<&str>,
45 file: Option<&str>,
46 line: Option<u32>,
47 ) -> String {
48 let mut text = Text::new("");
49
50 if self.show_time {
51 let now = chrono::Local::now();
52 let time_str = format!("[{}]", now.format("%H:%M:%S"));
53 text.append_styled(time_str, Style::new().dim(true));
54 text.append_styled(" ", Style::new());
55 }
56
57 if self.show_level {
58 let level_style = match level {
59 log::Level::Error => Style::new().color(crate::color::Color::parse("red").unwrap()).bold(true),
60 log::Level::Warn => Style::new().color(crate::color::Color::parse("yellow").unwrap()),
61 log::Level::Info => Style::new().color(crate::color::Color::parse("green").unwrap()),
62 log::Level::Debug => Style::new().color(crate::color::Color::parse("blue").unwrap()),
63 log::Level::Trace => Style::new().color(crate::color::Color::parse("bright_black").unwrap()),
64 };
65 text.append_styled(format!("{level:<5}"), level_style);
66 text.append_styled(" ", Style::new());
67 }
68
69 text.append_styled(message, Style::new());
71
72 if self.show_path {
74 if let (Some(file), Some(line)) = (file, line) {
75 text.append_styled(" ", Style::new());
76 let location = format!("{file}:{line}");
77 text.append_styled(format!("[{location}]"), Style::new().dim(true).italic(true));
78 }
79 }
80
81 text.render()
82 }
83
84 pub fn emit(&mut self, record: &log::Record) {
88 let formatted = self.render(
89 record.level(),
90 record.args().to_string().as_str(),
91 record.module_path(),
92 record.file(),
93 record.line(),
94 );
95 let _ = writeln!(self.console.file, "{formatted}");
96 let _ = self.console.file.flush();
97 }
98}
99
100impl Default for RichHandler {
101 fn default() -> Self {
102 Self::new()
103 }
104}
105
106pub fn install() -> Result<(), log::SetLoggerError> {
108 Ok(())
111}
112
113pub fn style_level(level: log::Level) -> Style {
115 match level {
116 log::Level::Error => Style::new()
117 .color(crate::color::Color::parse("red").unwrap())
118 .bold(true),
119 log::Level::Warn => Style::new()
120 .color(crate::color::Color::parse("yellow").unwrap()),
121 log::Level::Info => Style::new()
122 .color(crate::color::Color::parse("green").unwrap()),
123 log::Level::Debug => Style::new()
124 .color(crate::color::Color::parse("blue").unwrap()),
125 log::Level::Trace => Style::new()
126 .color(crate::color::Color::parse("bright_black").unwrap()),
127 }
128}