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