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}