pretty_env_logger/lib.rs
1#![cfg_attr(test, deny(warnings))]
2#![deny(missing_docs)]
3#![doc(html_root_url = "https://docs.rs/pretty_env_logger/0.5.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)]
40pub extern crate env_logger;
41
42extern crate log;
43
44use std::fmt;
45use std::sync::atomic::{AtomicUsize, Ordering};
46
47use env_logger::{
48 fmt::{Color, Style, StyledValue},
49 Builder,
50};
51use log::Level;
52
53/// Initializes the global logger with a pretty env logger.
54///
55/// This should be called early in the execution of a Rust program, and the
56/// global logger may only be initialized once. Future initialization attempts
57/// will return an error.
58///
59/// # Panics
60///
61/// This function fails to set the global logger if one has already been set.
62pub fn init() {
63 try_init().unwrap();
64}
65
66/// Initializes the global logger with a timed pretty env logger.
67///
68/// This should be called early in the execution of a Rust program, and the
69/// global logger may only be initialized once. Future initialization attempts
70/// will return an error.
71///
72/// # Panics
73///
74/// This function fails to set the global logger if one has already been set.
75pub fn init_timed() {
76 try_init_timed().unwrap();
77}
78
79/// Initializes the global logger with a pretty env logger.
80///
81/// This should be called early in the execution of a Rust program, and the
82/// global logger may only be initialized once. Future initialization attempts
83/// will return an error.
84///
85/// # Errors
86///
87/// This function fails to set the global logger if one has already been set.
88pub fn try_init() -> Result<(), log::SetLoggerError> {
89 try_init_custom_env("RUST_LOG")
90}
91
92/// Initializes the global logger with a timed pretty env logger.
93///
94/// This should be called early in the execution of a Rust program, and the
95/// global logger may only be initialized once. Future initialization attempts
96/// will return an error.
97///
98/// # Errors
99///
100/// This function fails to set the global logger if one has already been set.
101pub fn try_init_timed() -> Result<(), log::SetLoggerError> {
102 try_init_timed_custom_env("RUST_LOG")
103}
104
105/// Initialized the global logger with a pretty env logger, with a custom variable name.
106///
107/// This should be called early in the execution of a Rust program, and the
108/// global logger may only be initialized once. Future initialization attempts
109/// will return an error.
110///
111/// # Panics
112///
113/// This function fails to set the global logger if one has already been set.
114pub fn init_custom_env(environment_variable_name: &str) {
115 try_init_custom_env(environment_variable_name).unwrap();
116}
117
118/// Initialized the global logger with a pretty env logger, with a custom variable name.
119///
120/// This should be called early in the execution of a Rust program, and the
121/// global logger may only be initialized once. Future initialization attempts
122/// will return an error.
123///
124/// # Errors
125///
126/// This function fails to set the global logger if one has already been set.
127pub fn try_init_custom_env(environment_variable_name: &str) -> Result<(), log::SetLoggerError> {
128 let mut builder = formatted_builder();
129
130 if let Ok(s) = ::std::env::var(environment_variable_name) {
131 builder.parse_filters(&s);
132 }
133
134 builder.try_init()
135}
136
137/// Initialized the global logger with a timed pretty env logger, with a custom variable name.
138///
139/// This should be called early in the execution of a Rust program, and the
140/// global logger may only be initialized once. Future initialization attempts
141/// will return an error.
142///
143/// # Errors
144///
145/// This function fails to set the global logger if one has already been set.
146pub fn try_init_timed_custom_env(
147 environment_variable_name: &str,
148) -> Result<(), log::SetLoggerError> {
149 let mut builder = formatted_timed_builder();
150
151 if let Ok(s) = ::std::env::var(environment_variable_name) {
152 builder.parse_filters(&s);
153 }
154
155 builder.try_init()
156}
157
158/// Returns a `env_logger::Builder` for further customization.
159///
160/// This method will return a colored and formatted `env_logger::Builder`
161/// for further customization. Refer to env_logger::Build crate documentation
162/// for further details and usage.
163pub fn formatted_builder() -> Builder {
164 let mut builder = Builder::new();
165
166 builder.format(|f, record| {
167 use std::io::Write;
168
169 let target = record.target();
170 let max_width = max_target_width(target);
171
172 let mut style = f.style();
173 let level = colored_level(&mut style, record.level());
174
175 let mut style = f.style();
176 let target = style.set_bold(true).value(Padded {
177 value: target,
178 width: max_width,
179 });
180
181 writeln!(f, " {} {} > {}", level, target, record.args(),)
182 });
183
184 builder
185}
186
187/// Returns a `env_logger::Builder` for further customization.
188///
189/// This method will return a colored and time formatted `env_logger::Builder`
190/// for further customization. Refer to env_logger::Build crate documentation
191/// for further details and usage.
192pub fn formatted_timed_builder() -> Builder {
193 let mut builder = Builder::new();
194
195 builder.format(|f, record| {
196 use std::io::Write;
197 let target = record.target();
198 let max_width = max_target_width(target);
199
200 let mut style = f.style();
201 let level = colored_level(&mut style, record.level());
202
203 let mut style = f.style();
204 let target = style.set_bold(true).value(Padded {
205 value: target,
206 width: max_width,
207 });
208
209 let time = f.timestamp_millis();
210
211 writeln!(f, " {} {} {} > {}", time, level, target, record.args(),)
212 });
213
214 builder
215}
216
217struct Padded<T> {
218 value: T,
219 width: usize,
220}
221
222impl<T: fmt::Display> fmt::Display for Padded<T> {
223 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
224 write!(f, "{: <width$}", self.value, width = self.width)
225 }
226}
227
228static MAX_MODULE_WIDTH: AtomicUsize = AtomicUsize::new(0);
229
230fn max_target_width(target: &str) -> usize {
231 let max_width = MAX_MODULE_WIDTH.load(Ordering::Relaxed);
232 if max_width < target.len() {
233 MAX_MODULE_WIDTH.store(target.len(), Ordering::Relaxed);
234 target.len()
235 } else {
236 max_width
237 }
238}
239
240fn colored_level<'a>(style: &'a mut Style, level: Level) -> StyledValue<'a, &'static str> {
241 match level {
242 Level::Trace => style.set_color(Color::Magenta).value("TRACE"),
243 Level::Debug => style.set_color(Color::Blue).value("DEBUG"),
244 Level::Info => style.set_color(Color::Green).value("INFO "),
245 Level::Warn => style.set_color(Color::Yellow).value("WARN "),
246 Level::Error => style.set_color(Color::Red).value("ERROR"),
247 }
248}