1 #![cfg_attr(test, deny(warnings))]
2 #![deny(missing_docs)]
3 #![doc(html_root_url = "https://docs.rs/pretty_env_logger/0.4.0")]
4
5 //! A logger configured via an environment variable which writes to standard
6 //! error with nice colored output for log levels.
7 //!
8 //! ## Example
9 //!
10 //! ```
11 //! extern crate pretty_env_logger;
12 //! #[macro_use] extern crate log;
13 //!
14 //! fn main() {
15 //! pretty_env_logger::init();
16 //!
17 //! trace!("a trace example");
18 //! debug!("deboogging");
19 //! info!("such information");
20 //! warn!("o_O");
21 //! error!("boom");
22 //! }
23 //! ```
24 //!
25 //! Run the program with the environment variable `RUST_LOG=trace`.
26 //!
27 //! ## Defaults
28 //!
29 //! The defaults can be setup by calling `init()` or `try_init()` at the start
30 //! of the program.
31 //!
32 //! ## Enable logging
33 //!
34 //! This crate uses [env_logger][] internally, so the same ways of enabling
35 //! logs through an environment variable are supported.
36 //!
37 //! [env_logger]: https://docs.rs/env_logger
38
39 #[doc(hidden)]
40 pub extern crate env_logger;
41
42 extern crate log;
43
44 use std::fmt;
45 use std::sync::atomic::{AtomicUsize, Ordering};
46
47 use env_logger::{fmt::{Color, Style, StyledValue}, Builder};
48 use log::Level;
49
50
51 /// Initializes the global logger with a pretty env logger.
52 ///
53 /// This should be called early in the execution of a Rust program, and the
54 /// global logger may only be initialized once. Future initialization attempts
55 /// will return an error.
56 ///
57 /// # Panics
58 ///
59 /// This function fails to set the global logger if one has already been set.
init()60 pub fn init() {
61 try_init().unwrap();
62 }
63
64 /// Initializes the global logger with a timed pretty env logger.
65 ///
66 /// This should be called early in the execution of a Rust program, and the
67 /// global logger may only be initialized once. Future initialization attempts
68 /// will return an error.
69 ///
70 /// # Panics
71 ///
72 /// This function fails to set the global logger if one has already been set.
init_timed()73 pub fn init_timed() {
74 try_init_timed().unwrap();
75 }
76
77 /// Initializes the global logger with a pretty env logger.
78 ///
79 /// This should be called early in the execution of a Rust program, and the
80 /// global logger may only be initialized once. Future initialization attempts
81 /// will return an error.
82 ///
83 /// # Errors
84 ///
85 /// This function fails to set the global logger if one has already been set.
try_init() -> Result<(), log::SetLoggerError>86 pub fn try_init() -> Result<(), log::SetLoggerError> {
87 try_init_custom_env("RUST_LOG")
88 }
89
90 /// Initializes the global logger with a timed pretty env logger.
91 ///
92 /// This should be called early in the execution of a Rust program, and the
93 /// global logger may only be initialized once. Future initialization attempts
94 /// will return an error.
95 ///
96 /// # Errors
97 ///
98 /// This function fails to set the global logger if one has already been set.
try_init_timed() -> Result<(), log::SetLoggerError>99 pub fn try_init_timed() -> Result<(), log::SetLoggerError> {
100 try_init_timed_custom_env("RUST_LOG")
101 }
102
103 /// Initialized the global logger with a pretty env logger, with a custom variable name.
104 ///
105 /// This should be called early in the execution of a Rust program, and the
106 /// global logger may only be initialized once. Future initialization attempts
107 /// will return an error.
108 ///
109 /// # Panics
110 ///
111 /// This function fails to set the global logger if one has already been set.
init_custom_env(environment_variable_name: &str)112 pub fn init_custom_env(environment_variable_name: &str) {
113 try_init_custom_env(environment_variable_name).unwrap();
114 }
115
116 /// Initialized the global logger with a pretty env logger, with a custom variable name.
117 ///
118 /// This should be called early in the execution of a Rust program, and the
119 /// global logger may only be initialized once. Future initialization attempts
120 /// will return an error.
121 ///
122 /// # Errors
123 ///
124 /// This function fails to set the global logger if one has already been set.
try_init_custom_env(environment_variable_name: &str) -> Result<(), log::SetLoggerError>125 pub fn try_init_custom_env(environment_variable_name: &str) -> Result<(), log::SetLoggerError> {
126 let mut builder = formatted_builder();
127
128 if let Ok(s) = ::std::env::var(environment_variable_name) {
129 builder.parse_filters(&s);
130 }
131
132 builder.try_init()
133 }
134
135 /// Initialized the global logger with a timed pretty env logger, with a custom variable name.
136 ///
137 /// This should be called early in the execution of a Rust program, and the
138 /// global logger may only be initialized once. Future initialization attempts
139 /// will return an error.
140 ///
141 /// # Errors
142 ///
143 /// This function fails to set the global logger if one has already been set.
try_init_timed_custom_env(environment_variable_name: &str) -> Result<(), log::SetLoggerError>144 pub fn try_init_timed_custom_env(environment_variable_name: &str) -> Result<(), log::SetLoggerError> {
145 let mut builder = formatted_timed_builder();
146
147 if let Ok(s) = ::std::env::var(environment_variable_name) {
148 builder.parse_filters(&s);
149 }
150
151 builder.try_init()
152 }
153
154 /// Returns a `env_logger::Builder` for further customization.
155 ///
156 /// This method will return a colored and formatted `env_logger::Builder`
157 /// for further customization. Refer to env_logger::Build crate documentation
158 /// for further details and usage.
formatted_builder() -> Builder159 pub fn formatted_builder() -> Builder {
160 let mut builder = Builder::new();
161
162 builder.format(|f, record| {
163 use std::io::Write;
164
165 let target = record.target();
166 let max_width = max_target_width(target);
167
168 let mut style = f.style();
169 let level = colored_level(&mut style, record.level());
170
171 let mut style = f.style();
172 let target = style.set_bold(true).value(Padded {
173 value: target,
174 width: max_width,
175 });
176
177 writeln!(
178 f,
179 " {} {} > {}",
180 level,
181 target,
182 record.args(),
183 )
184 });
185
186 builder
187 }
188
189 /// Returns a `env_logger::Builder` for further customization.
190 ///
191 /// This method will return a colored and time formatted `env_logger::Builder`
192 /// for further customization. Refer to env_logger::Build crate documentation
193 /// for further details and usage.
formatted_timed_builder() -> Builder194 pub fn formatted_timed_builder() -> Builder {
195 let mut builder = Builder::new();
196
197 builder.format(|f, record| {
198 use std::io::Write;
199 let target = record.target();
200 let max_width = max_target_width(target);
201
202 let mut style = f.style();
203 let level = colored_level(&mut style, record.level());
204
205 let mut style = f.style();
206 let target = style.set_bold(true).value(Padded {
207 value: target,
208 width: max_width,
209 });
210
211 let time = f.timestamp_millis();
212
213 writeln!(
214 f,
215 " {} {} {} > {}",
216 time,
217 level,
218 target,
219 record.args(),
220 )
221 });
222
223 builder
224 }
225
226 struct Padded<T> {
227 value: T,
228 width: usize,
229 }
230
231 impl<T: fmt::Display> fmt::Display for Padded<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result232 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
233 write!(f, "{: <width$}", self.value, width=self.width)
234 }
235 }
236
237 static MAX_MODULE_WIDTH: AtomicUsize = AtomicUsize::new(0);
238
max_target_width(target: &str) -> usize239 fn max_target_width(target: &str) -> usize {
240 let max_width = MAX_MODULE_WIDTH.load(Ordering::Relaxed);
241 if max_width < target.len() {
242 MAX_MODULE_WIDTH.store(target.len(), Ordering::Relaxed);
243 target.len()
244 } else {
245 max_width
246 }
247 }
248
colored_level<'a>(style: &'a mut Style, level: Level) -> StyledValue<'a, &'static str>249 fn colored_level<'a>(style: &'a mut Style, level: Level) -> StyledValue<'a, &'static str> {
250 match level {
251 Level::Trace => style.set_color(Color::Magenta).value("TRACE"),
252 Level::Debug => style.set_color(Color::Blue).value("DEBUG"),
253 Level::Info => style.set_color(Color::Green).value("INFO "),
254 Level::Warn => style.set_color(Color::Yellow).value("WARN "),
255 Level::Error => style.set_color(Color::Red).value("ERROR"),
256 }
257 }
258