1use std::io::Write;
6
7use crate::console::Console;
8#[cfg(feature = "syntax-highlighting")]
9use crate::highlighter::ReprHighlighter;
10use crate::style::Style;
11use crate::text::Text;
12
13pub struct RichHandler {
17 pub console: Console,
18 pub show_time: bool,
19 pub show_level: bool,
20 pub show_path: bool,
21 pub enable_link_path: bool,
22 pub markup: bool,
23 #[cfg(feature = "syntax-highlighting")]
24 pub highlighter: ReprHighlighter,
25}
26
27impl RichHandler {
28 pub fn new() -> Self {
30 Self {
31 console: Console::new(),
32 show_time: true,
33 show_level: true,
34 show_path: true,
35 enable_link_path: false,
36 markup: false,
37 #[cfg(feature = "syntax-highlighting")]
38 highlighter: ReprHighlighter::new(),
39 }
40 }
41
42 pub fn render(
44 &self,
45 level: log::Level,
46 message: &str,
47 _module_path: Option<&str>,
48 file: Option<&str>,
49 line: Option<u32>,
50 ) -> String {
51 let mut text = Text::new("");
52
53 if self.show_time {
54 let now = chrono::Local::now();
55 let time_str = format!("[{}]", now.format("%H:%M:%S"));
56 text.append_styled(time_str, Style::new().dim(true));
57 text.append_styled(" ", Style::new());
58 }
59
60 if self.show_level {
61 let level_style = match level {
62 log::Level::Error => Style::new()
63 .color(crate::color::Color::parse("red").unwrap())
64 .bold(true),
65 log::Level::Warn => {
66 Style::new().color(crate::color::Color::parse("yellow").unwrap())
67 }
68 log::Level::Info => {
69 Style::new().color(crate::color::Color::parse("green").unwrap())
70 }
71 log::Level::Debug => {
72 Style::new().color(crate::color::Color::parse("blue").unwrap())
73 }
74 log::Level::Trace => {
75 Style::new().color(crate::color::Color::parse("bright_black").unwrap())
76 }
77 };
78 text.append_styled(format!("{level:<5}"), level_style);
79 text.append_styled(" ", Style::new());
80 }
81
82 text.append_styled(message, Style::new());
84
85 if self.show_path {
87 if let (Some(file), Some(line)) = (file, line) {
88 text.append_styled(" ", Style::new());
89 let location = format!("{file}:{line}");
90 text.append_styled(format!("[{location}]"), Style::new().dim(true).italic(true));
91 }
92 }
93
94 text.render()
95 }
96
97 pub fn emit(&mut self, record: &log::Record) {
101 let formatted = self.render(
102 record.level(),
103 record.args().to_string().as_str(),
104 record.module_path(),
105 record.file(),
106 record.line(),
107 );
108 let _ = writeln!(self.console.file, "{formatted}");
109 let _ = self.console.file.flush();
110 }
111}
112
113impl Default for RichHandler {
114 fn default() -> Self {
115 Self::new()
116 }
117}
118
119pub fn install() -> Result<(), log::SetLoggerError> {
121 Ok(())
124}
125
126pub fn style_level(level: log::Level) -> Style {
128 match level {
129 log::Level::Error => Style::new()
130 .color(crate::color::Color::parse("red").unwrap())
131 .bold(true),
132 log::Level::Warn => Style::new().color(crate::color::Color::parse("yellow").unwrap()),
133 log::Level::Info => Style::new().color(crate::color::Color::parse("green").unwrap()),
134 log::Level::Debug => Style::new().color(crate::color::Color::parse("blue").unwrap()),
135 log::Level::Trace => {
136 Style::new().color(crate::color::Color::parse("bright_black").unwrap())
137 }
138 }
139}