| 1 | use std::{borrow::Cow, cell::RefCell, env, io}; |
|---|---|
| 2 | |
| 3 | use log::{LevelFilter, Log, Metadata, Record, SetLoggerError}; |
| 4 | |
| 5 | use crate::fmt; |
| 6 | use crate::fmt::writer::{self, Writer}; |
| 7 | use crate::fmt::{FormatFn, Formatter}; |
| 8 | |
| 9 | /// The default name for the environment variable to read filters from. |
| 10 | pub const DEFAULT_FILTER_ENV: &str = "RUST_LOG"; |
| 11 | |
| 12 | /// The default name for the environment variable to read style preferences from. |
| 13 | pub const DEFAULT_WRITE_STYLE_ENV: &str = "RUST_LOG_STYLE"; |
| 14 | |
| 15 | /// `Builder` acts as builder for initializing a `Logger`. |
| 16 | /// |
| 17 | /// It can be used to customize the log format, change the environment variable used |
| 18 | /// to provide the logging directives and also set the default log level filter. |
| 19 | /// |
| 20 | /// # Examples |
| 21 | /// |
| 22 | /// ``` |
| 23 | /// # use std::io::Write; |
| 24 | /// use env_logger::Builder; |
| 25 | /// use log::{LevelFilter, error, info}; |
| 26 | /// |
| 27 | /// let mut builder = Builder::from_default_env(); |
| 28 | /// |
| 29 | /// builder |
| 30 | /// .format(|buf, record| writeln!(buf, "{} - {}", record.level(), record.args())) |
| 31 | /// .filter(None, LevelFilter::Info) |
| 32 | /// .init(); |
| 33 | /// |
| 34 | /// error!("error message"); |
| 35 | /// info!("info message"); |
| 36 | /// ``` |
| 37 | #[derive(Default)] |
| 38 | pub struct Builder { |
| 39 | filter: env_filter::Builder, |
| 40 | writer: writer::Builder, |
| 41 | format: fmt::Builder, |
| 42 | built: bool, |
| 43 | } |
| 44 | |
| 45 | impl Builder { |
| 46 | /// Initializes the log builder with defaults. |
| 47 | /// |
| 48 | /// **NOTE:** This method won't read from any environment variables. |
| 49 | /// Use the [`filter`] and [`write_style`] methods to configure the builder |
| 50 | /// or use [`from_env`] or [`from_default_env`] instead. |
| 51 | /// |
| 52 | /// # Examples |
| 53 | /// |
| 54 | /// Create a new builder and configure filters and style: |
| 55 | /// |
| 56 | /// ``` |
| 57 | /// use log::LevelFilter; |
| 58 | /// use env_logger::{Builder, WriteStyle}; |
| 59 | /// |
| 60 | /// let mut builder = Builder::new(); |
| 61 | /// |
| 62 | /// builder |
| 63 | /// .filter(None, LevelFilter::Info) |
| 64 | /// .write_style(WriteStyle::Always) |
| 65 | /// .init(); |
| 66 | /// ``` |
| 67 | /// |
| 68 | /// [`filter`]: #method.filter |
| 69 | /// [`write_style`]: #method.write_style |
| 70 | /// [`from_env`]: #method.from_env |
| 71 | /// [`from_default_env`]: #method.from_default_env |
| 72 | pub fn new() -> Builder { |
| 73 | Default::default() |
| 74 | } |
| 75 | |
| 76 | /// Initializes the log builder from the environment. |
| 77 | /// |
| 78 | /// The variables used to read configuration from can be tweaked before |
| 79 | /// passing in. |
| 80 | /// |
| 81 | /// # Examples |
| 82 | /// |
| 83 | /// Initialise a logger reading the log filter from an environment variable |
| 84 | /// called `MY_LOG`: |
| 85 | /// |
| 86 | /// ``` |
| 87 | /// use env_logger::Builder; |
| 88 | /// |
| 89 | /// let mut builder = Builder::from_env("MY_LOG"); |
| 90 | /// builder.init(); |
| 91 | /// ``` |
| 92 | /// |
| 93 | /// Initialise a logger using the `MY_LOG` variable for filtering and |
| 94 | /// `MY_LOG_STYLE` for whether or not to write styles: |
| 95 | /// |
| 96 | /// ``` |
| 97 | /// use env_logger::{Builder, Env}; |
| 98 | /// |
| 99 | /// let env = Env::new().filter("MY_LOG").write_style( "MY_LOG_STYLE"); |
| 100 | /// |
| 101 | /// let mut builder = Builder::from_env(env); |
| 102 | /// builder.init(); |
| 103 | /// ``` |
| 104 | pub fn from_env<'a, E>(env: E) -> Self |
| 105 | where |
| 106 | E: Into<Env<'a>>, |
| 107 | { |
| 108 | let mut builder = Builder::new(); |
| 109 | builder.parse_env(env); |
| 110 | builder |
| 111 | } |
| 112 | |
| 113 | /// Applies the configuration from the environment. |
| 114 | /// |
| 115 | /// This function allows a builder to be configured with default parameters, |
| 116 | /// to be then overridden by the environment. |
| 117 | /// |
| 118 | /// # Examples |
| 119 | /// |
| 120 | /// Initialise a logger with filter level `Off`, then override the log |
| 121 | /// filter from an environment variable called `MY_LOG`: |
| 122 | /// |
| 123 | /// ``` |
| 124 | /// use log::LevelFilter; |
| 125 | /// use env_logger::Builder; |
| 126 | /// |
| 127 | /// let mut builder = Builder::new(); |
| 128 | /// |
| 129 | /// builder.filter_level(LevelFilter::Off); |
| 130 | /// builder.parse_env("MY_LOG"); |
| 131 | /// builder.init(); |
| 132 | /// ``` |
| 133 | /// |
| 134 | /// Initialise a logger with filter level `Off`, then use the `MY_LOG` |
| 135 | /// variable to override filtering and `MY_LOG_STYLE` to override whether |
| 136 | /// or not to write styles: |
| 137 | /// |
| 138 | /// ``` |
| 139 | /// use log::LevelFilter; |
| 140 | /// use env_logger::{Builder, Env}; |
| 141 | /// |
| 142 | /// let env = Env::new().filter("MY_LOG").write_style( "MY_LOG_STYLE"); |
| 143 | /// |
| 144 | /// let mut builder = Builder::new(); |
| 145 | /// builder.filter_level(LevelFilter::Off); |
| 146 | /// builder.parse_env(env); |
| 147 | /// builder.init(); |
| 148 | /// ``` |
| 149 | pub fn parse_env<'a, E>(&mut self, env: E) -> &mut Self |
| 150 | where |
| 151 | E: Into<Env<'a>>, |
| 152 | { |
| 153 | let env = env.into(); |
| 154 | |
| 155 | if let Some(s) = env.get_filter() { |
| 156 | self.parse_filters(&s); |
| 157 | } |
| 158 | |
| 159 | if let Some(s) = env.get_write_style() { |
| 160 | self.parse_write_style(&s); |
| 161 | } |
| 162 | |
| 163 | self |
| 164 | } |
| 165 | |
| 166 | /// Initializes the log builder from the environment using default variable names. |
| 167 | /// |
| 168 | /// This method is a convenient way to call `from_env(Env::default())` without |
| 169 | /// having to use the `Env` type explicitly. The builder will use the |
| 170 | /// [default environment variables]. |
| 171 | /// |
| 172 | /// # Examples |
| 173 | /// |
| 174 | /// Initialise a logger using the default environment variables: |
| 175 | /// |
| 176 | /// ``` |
| 177 | /// use env_logger::Builder; |
| 178 | /// |
| 179 | /// let mut builder = Builder::from_default_env(); |
| 180 | /// builder.init(); |
| 181 | /// ``` |
| 182 | /// |
| 183 | /// [default environment variables]: struct.Env.html#default-environment-variables |
| 184 | pub fn from_default_env() -> Self { |
| 185 | Self::from_env(Env::default()) |
| 186 | } |
| 187 | |
| 188 | /// Applies the configuration from the environment using default variable names. |
| 189 | /// |
| 190 | /// This method is a convenient way to call `parse_env(Env::default())` without |
| 191 | /// having to use the `Env` type explicitly. The builder will use the |
| 192 | /// [default environment variables]. |
| 193 | /// |
| 194 | /// # Examples |
| 195 | /// |
| 196 | /// Initialise a logger with filter level `Off`, then configure it using the |
| 197 | /// default environment variables: |
| 198 | /// |
| 199 | /// ``` |
| 200 | /// use log::LevelFilter; |
| 201 | /// use env_logger::Builder; |
| 202 | /// |
| 203 | /// let mut builder = Builder::new(); |
| 204 | /// builder.filter_level(LevelFilter::Off); |
| 205 | /// builder.parse_default_env(); |
| 206 | /// builder.init(); |
| 207 | /// ``` |
| 208 | /// |
| 209 | /// [default environment variables]: struct.Env.html#default-environment-variables |
| 210 | pub fn parse_default_env(&mut self) -> &mut Self { |
| 211 | self.parse_env(Env::default()) |
| 212 | } |
| 213 | |
| 214 | /// Sets the format function for formatting the log output. |
| 215 | /// |
| 216 | /// This function is called on each record logged and should format the |
| 217 | /// log record and output it to the given [`Formatter`]. |
| 218 | /// |
| 219 | /// The format function is expected to output the string directly to the |
| 220 | /// `Formatter` so that implementations can use the [`std::fmt`] macros |
| 221 | /// to format and output without intermediate heap allocations. The default |
| 222 | /// `env_logger` formatter takes advantage of this. |
| 223 | /// |
| 224 | /// When the `color` feature is enabled, styling via ANSI escape codes is supported and the |
| 225 | /// output will automatically respect [`Builder::write_style`]. |
| 226 | /// |
| 227 | /// # Examples |
| 228 | /// |
| 229 | /// Use a custom format to write only the log message: |
| 230 | /// |
| 231 | /// ``` |
| 232 | /// use std::io::Write; |
| 233 | /// use env_logger::Builder; |
| 234 | /// |
| 235 | /// let mut builder = Builder::new(); |
| 236 | /// |
| 237 | /// builder.format(|buf, record| writeln!(buf, "{}", record.args())); |
| 238 | /// ``` |
| 239 | /// |
| 240 | /// [`Formatter`]: fmt/struct.Formatter.html |
| 241 | /// [`String`]: https://doc.rust-lang.org/stable/std/string/struct.String.html |
| 242 | /// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html |
| 243 | pub fn format<F>(&mut self, format: F) -> &mut Self |
| 244 | where |
| 245 | F: Fn(&mut Formatter, &Record<'_>) -> io::Result<()> + Sync + Send + 'static, |
| 246 | { |
| 247 | self.format.custom_format = Some(Box::new(format)); |
| 248 | self |
| 249 | } |
| 250 | |
| 251 | /// Use the default format. |
| 252 | /// |
| 253 | /// This method will clear any custom format set on the builder. |
| 254 | pub fn default_format(&mut self) -> &mut Self { |
| 255 | self.format = Default::default(); |
| 256 | self |
| 257 | } |
| 258 | |
| 259 | /// Whether or not to write the level in the default format. |
| 260 | pub fn format_level(&mut self, write: bool) -> &mut Self { |
| 261 | self.format.format_level = write; |
| 262 | self |
| 263 | } |
| 264 | |
| 265 | /// Whether or not to write the source file path in the default format. |
| 266 | pub fn format_file(&mut self, write: bool) -> &mut Self { |
| 267 | self.format.format_file = write; |
| 268 | self |
| 269 | } |
| 270 | |
| 271 | /// Whether or not to write the source line number path in the default format. |
| 272 | /// |
| 273 | /// Only has effect if `format_file` is also enabled |
| 274 | pub fn format_line_number(&mut self, write: bool) -> &mut Self { |
| 275 | self.format.format_line_number = write; |
| 276 | self |
| 277 | } |
| 278 | |
| 279 | /// Whether or not to write the source path and line number |
| 280 | /// |
| 281 | /// Equivalent to calling both `format_file` and `format_line_number` |
| 282 | /// with `true` |
| 283 | pub fn format_source_path(&mut self, write: bool) -> &mut Self { |
| 284 | self.format_file(write).format_line_number(write); |
| 285 | self |
| 286 | } |
| 287 | |
| 288 | /// Whether or not to write the module path in the default format. |
| 289 | pub fn format_module_path(&mut self, write: bool) -> &mut Self { |
| 290 | self.format.format_module_path = write; |
| 291 | self |
| 292 | } |
| 293 | |
| 294 | /// Whether or not to write the target in the default format. |
| 295 | pub fn format_target(&mut self, write: bool) -> &mut Self { |
| 296 | self.format.format_target = write; |
| 297 | self |
| 298 | } |
| 299 | |
| 300 | /// Configures the amount of spaces to use to indent multiline log records. |
| 301 | /// A value of `None` disables any kind of indentation. |
| 302 | pub fn format_indent(&mut self, indent: Option<usize>) -> &mut Self { |
| 303 | self.format.format_indent = indent; |
| 304 | self |
| 305 | } |
| 306 | |
| 307 | /// Configures if timestamp should be included and in what precision. |
| 308 | pub fn format_timestamp(&mut self, timestamp: Option<fmt::TimestampPrecision>) -> &mut Self { |
| 309 | self.format.format_timestamp = timestamp; |
| 310 | self |
| 311 | } |
| 312 | |
| 313 | /// Configures the timestamp to use second precision. |
| 314 | pub fn format_timestamp_secs(&mut self) -> &mut Self { |
| 315 | self.format_timestamp(Some(fmt::TimestampPrecision::Seconds)) |
| 316 | } |
| 317 | |
| 318 | /// Configures the timestamp to use millisecond precision. |
| 319 | pub fn format_timestamp_millis(&mut self) -> &mut Self { |
| 320 | self.format_timestamp(Some(fmt::TimestampPrecision::Millis)) |
| 321 | } |
| 322 | |
| 323 | /// Configures the timestamp to use microsecond precision. |
| 324 | pub fn format_timestamp_micros(&mut self) -> &mut Self { |
| 325 | self.format_timestamp(Some(fmt::TimestampPrecision::Micros)) |
| 326 | } |
| 327 | |
| 328 | /// Configures the timestamp to use nanosecond precision. |
| 329 | pub fn format_timestamp_nanos(&mut self) -> &mut Self { |
| 330 | self.format_timestamp(Some(fmt::TimestampPrecision::Nanos)) |
| 331 | } |
| 332 | |
| 333 | /// Configures the end of line suffix. |
| 334 | pub fn format_suffix(&mut self, suffix: &'static str) -> &mut Self { |
| 335 | self.format.format_suffix = suffix; |
| 336 | self |
| 337 | } |
| 338 | |
| 339 | /// Set the format for structured key/value pairs in the log record |
| 340 | /// |
| 341 | /// With the default format, this function is called for each record and should format |
| 342 | /// the structured key-value pairs as returned by [`log::Record::key_values`]. |
| 343 | /// |
| 344 | /// The format function is expected to output the string directly to the `Formatter` so that |
| 345 | /// implementations can use the [`std::fmt`] macros, similar to the main format function. |
| 346 | /// |
| 347 | /// The default format uses a space to separate each key-value pair, with an "=" between |
| 348 | /// the key and value. |
| 349 | #[cfg(feature = "unstable-kv")] |
| 350 | pub fn format_key_values<F>(&mut self, format: F) -> &mut Self |
| 351 | where |
| 352 | F: Fn(&mut Formatter, &dyn log::kv::Source) -> io::Result<()> + Sync + Send + 'static, |
| 353 | { |
| 354 | self.format.kv_format = Some(Box::new(format)); |
| 355 | self |
| 356 | } |
| 357 | |
| 358 | /// Adds a directive to the filter for a specific module. |
| 359 | /// |
| 360 | /// # Examples |
| 361 | /// |
| 362 | /// Only include messages for info and above for logs in `path::to::module`: |
| 363 | /// |
| 364 | /// ``` |
| 365 | /// use env_logger::Builder; |
| 366 | /// use log::LevelFilter; |
| 367 | /// |
| 368 | /// let mut builder = Builder::new(); |
| 369 | /// |
| 370 | /// builder.filter_module("path::to::module", LevelFilter::Info); |
| 371 | /// ``` |
| 372 | pub fn filter_module(&mut self, module: &str, level: LevelFilter) -> &mut Self { |
| 373 | self.filter.filter_module(module, level); |
| 374 | self |
| 375 | } |
| 376 | |
| 377 | /// Adds a directive to the filter for all modules. |
| 378 | /// |
| 379 | /// # Examples |
| 380 | /// |
| 381 | /// Only include messages for info and above for logs globally: |
| 382 | /// |
| 383 | /// ``` |
| 384 | /// use env_logger::Builder; |
| 385 | /// use log::LevelFilter; |
| 386 | /// |
| 387 | /// let mut builder = Builder::new(); |
| 388 | /// |
| 389 | /// builder.filter_level(LevelFilter::Info); |
| 390 | /// ``` |
| 391 | pub fn filter_level(&mut self, level: LevelFilter) -> &mut Self { |
| 392 | self.filter.filter_level(level); |
| 393 | self |
| 394 | } |
| 395 | |
| 396 | /// Adds filters to the logger. |
| 397 | /// |
| 398 | /// The given module (if any) will log at most the specified level provided. |
| 399 | /// If no module is provided then the filter will apply to all log messages. |
| 400 | /// |
| 401 | /// # Examples |
| 402 | /// |
| 403 | /// Only include messages for info and above for logs in `path::to::module`: |
| 404 | /// |
| 405 | /// ``` |
| 406 | /// use env_logger::Builder; |
| 407 | /// use log::LevelFilter; |
| 408 | /// |
| 409 | /// let mut builder = Builder::new(); |
| 410 | /// |
| 411 | /// builder.filter(Some("path::to::module"), LevelFilter::Info); |
| 412 | /// ``` |
| 413 | pub fn filter(&mut self, module: Option<&str>, level: LevelFilter) -> &mut Self { |
| 414 | self.filter.filter(module, level); |
| 415 | self |
| 416 | } |
| 417 | |
| 418 | /// Parses the directives string in the same form as the `RUST_LOG` |
| 419 | /// environment variable. |
| 420 | /// |
| 421 | /// See the module documentation for more details. |
| 422 | pub fn parse_filters(&mut self, filters: &str) -> &mut Self { |
| 423 | self.filter.parse(filters); |
| 424 | self |
| 425 | } |
| 426 | |
| 427 | /// Sets the target for the log output. |
| 428 | /// |
| 429 | /// Env logger can log to either stdout, stderr or a custom pipe. The default is stderr. |
| 430 | /// |
| 431 | /// The custom pipe can be used to send the log messages to a custom sink (for example a file). |
| 432 | /// Do note that direct writes to a file can become a bottleneck due to IO operation times. |
| 433 | /// |
| 434 | /// # Examples |
| 435 | /// |
| 436 | /// Write log message to `stdout`: |
| 437 | /// |
| 438 | /// ``` |
| 439 | /// use env_logger::{Builder, Target}; |
| 440 | /// |
| 441 | /// let mut builder = Builder::new(); |
| 442 | /// |
| 443 | /// builder.target(Target::Stdout); |
| 444 | /// ``` |
| 445 | pub fn target(&mut self, target: fmt::Target) -> &mut Self { |
| 446 | self.writer.target(target); |
| 447 | self |
| 448 | } |
| 449 | |
| 450 | /// Sets whether or not styles will be written. |
| 451 | /// |
| 452 | /// This can be useful in environments that don't support control characters |
| 453 | /// for setting colors. |
| 454 | /// |
| 455 | /// # Examples |
| 456 | /// |
| 457 | /// Never attempt to write styles: |
| 458 | /// |
| 459 | /// ``` |
| 460 | /// use env_logger::{Builder, WriteStyle}; |
| 461 | /// |
| 462 | /// let mut builder = Builder::new(); |
| 463 | /// |
| 464 | /// builder.write_style(WriteStyle::Never); |
| 465 | /// ``` |
| 466 | pub fn write_style(&mut self, write_style: fmt::WriteStyle) -> &mut Self { |
| 467 | self.writer.write_style(write_style); |
| 468 | self |
| 469 | } |
| 470 | |
| 471 | /// Parses whether or not to write styles in the same form as the `RUST_LOG_STYLE` |
| 472 | /// environment variable. |
| 473 | /// |
| 474 | /// See the module documentation for more details. |
| 475 | pub fn parse_write_style(&mut self, write_style: &str) -> &mut Self { |
| 476 | self.writer.parse_write_style(write_style); |
| 477 | self |
| 478 | } |
| 479 | |
| 480 | /// Sets whether or not the logger will be used in unit tests. |
| 481 | /// |
| 482 | /// If `is_test` is `true` then the logger will allow the testing framework to |
| 483 | /// capture log records rather than printing them to the terminal directly. |
| 484 | pub fn is_test(&mut self, is_test: bool) -> &mut Self { |
| 485 | self.writer.is_test(is_test); |
| 486 | self |
| 487 | } |
| 488 | |
| 489 | /// Initializes the global logger with the built env logger. |
| 490 | /// |
| 491 | /// This should be called early in the execution of a Rust program. Any log |
| 492 | /// events that occur before initialization will be ignored. |
| 493 | /// |
| 494 | /// # Errors |
| 495 | /// |
| 496 | /// This function will fail if it is called more than once, or if another |
| 497 | /// library has already initialized a global logger. |
| 498 | pub fn try_init(&mut self) -> Result<(), SetLoggerError> { |
| 499 | let logger = self.build(); |
| 500 | |
| 501 | let max_level = logger.filter(); |
| 502 | let r = log::set_boxed_logger(Box::new(logger)); |
| 503 | |
| 504 | if r.is_ok() { |
| 505 | log::set_max_level(max_level); |
| 506 | } |
| 507 | |
| 508 | r |
| 509 | } |
| 510 | |
| 511 | /// Initializes the global logger with the built env logger. |
| 512 | /// |
| 513 | /// This should be called early in the execution of a Rust program. Any log |
| 514 | /// events that occur before initialization will be ignored. |
| 515 | /// |
| 516 | /// # Panics |
| 517 | /// |
| 518 | /// This function will panic if it is called more than once, or if another |
| 519 | /// library has already initialized a global logger. |
| 520 | pub fn init(&mut self) { |
| 521 | self.try_init() |
| 522 | .expect("Builder::init should not be called after logger initialized"); |
| 523 | } |
| 524 | |
| 525 | /// Build an env logger. |
| 526 | /// |
| 527 | /// The returned logger implements the `Log` trait and can be installed manually |
| 528 | /// or nested within another logger. |
| 529 | pub fn build(&mut self) -> Logger { |
| 530 | assert!(!self.built, "attempt to re-use consumed builder"); |
| 531 | self.built = true; |
| 532 | |
| 533 | Logger { |
| 534 | writer: self.writer.build(), |
| 535 | filter: self.filter.build(), |
| 536 | format: self.format.build(), |
| 537 | } |
| 538 | } |
| 539 | } |
| 540 | |
| 541 | impl std::fmt::Debug for Builder { |
| 542 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 543 | if self.built { |
| 544 | f.debug_struct("Logger").field(name: "built", &true).finish() |
| 545 | } else { |
| 546 | f&mut DebugStruct<'_, '_>.debug_struct("Logger") |
| 547 | .field("filter", &self.filter) |
| 548 | .field(name:"writer", &self.writer) |
| 549 | .finish() |
| 550 | } |
| 551 | } |
| 552 | } |
| 553 | |
| 554 | /// The env logger. |
| 555 | /// |
| 556 | /// This struct implements the `Log` trait from the [`log` crate][log-crate-url], |
| 557 | /// which allows it to act as a logger. |
| 558 | /// |
| 559 | /// The [`init()`], [`try_init()`], [`Builder::init()`] and [`Builder::try_init()`] |
| 560 | /// methods will each construct a `Logger` and immediately initialize it as the |
| 561 | /// default global logger. |
| 562 | /// |
| 563 | /// If you'd instead need access to the constructed `Logger`, you can use |
| 564 | /// the associated [`Builder`] and install it with the |
| 565 | /// [`log` crate][log-crate-url] directly. |
| 566 | /// |
| 567 | /// [log-crate-url]: https://docs.rs/log |
| 568 | /// [`init()`]: fn.init.html |
| 569 | /// [`try_init()`]: fn.try_init.html |
| 570 | /// [`Builder::init()`]: struct.Builder.html#method.init |
| 571 | /// [`Builder::try_init()`]: struct.Builder.html#method.try_init |
| 572 | /// [`Builder`]: struct.Builder.html |
| 573 | pub struct Logger { |
| 574 | writer: Writer, |
| 575 | filter: env_filter::Filter, |
| 576 | format: FormatFn, |
| 577 | } |
| 578 | |
| 579 | impl Logger { |
| 580 | /// Creates the logger from the environment. |
| 581 | /// |
| 582 | /// The variables used to read configuration from can be tweaked before |
| 583 | /// passing in. |
| 584 | /// |
| 585 | /// # Examples |
| 586 | /// |
| 587 | /// Create a logger reading the log filter from an environment variable |
| 588 | /// called `MY_LOG`: |
| 589 | /// |
| 590 | /// ``` |
| 591 | /// use env_logger::Logger; |
| 592 | /// |
| 593 | /// let logger = Logger::from_env("MY_LOG"); |
| 594 | /// ``` |
| 595 | /// |
| 596 | /// Create a logger using the `MY_LOG` variable for filtering and |
| 597 | /// `MY_LOG_STYLE` for whether or not to write styles: |
| 598 | /// |
| 599 | /// ``` |
| 600 | /// use env_logger::{Logger, Env}; |
| 601 | /// |
| 602 | /// let env = Env::new().filter_or("MY_LOG", "info").write_style_or( "MY_LOG_STYLE", "always"); |
| 603 | /// |
| 604 | /// let logger = Logger::from_env(env); |
| 605 | /// ``` |
| 606 | pub fn from_env<'a, E>(env: E) -> Self |
| 607 | where |
| 608 | E: Into<Env<'a>>, |
| 609 | { |
| 610 | Builder::from_env(env).build() |
| 611 | } |
| 612 | |
| 613 | /// Creates the logger from the environment using default variable names. |
| 614 | /// |
| 615 | /// This method is a convenient way to call `from_env(Env::default())` without |
| 616 | /// having to use the `Env` type explicitly. The logger will use the |
| 617 | /// [default environment variables]. |
| 618 | /// |
| 619 | /// # Examples |
| 620 | /// |
| 621 | /// Creates a logger using the default environment variables: |
| 622 | /// |
| 623 | /// ``` |
| 624 | /// use env_logger::Logger; |
| 625 | /// |
| 626 | /// let logger = Logger::from_default_env(); |
| 627 | /// ``` |
| 628 | /// |
| 629 | /// [default environment variables]: struct.Env.html#default-environment-variables |
| 630 | pub fn from_default_env() -> Self { |
| 631 | Builder::from_default_env().build() |
| 632 | } |
| 633 | |
| 634 | /// Returns the maximum `LevelFilter` that this env logger instance is |
| 635 | /// configured to output. |
| 636 | pub fn filter(&self) -> LevelFilter { |
| 637 | self.filter.filter() |
| 638 | } |
| 639 | |
| 640 | /// Checks if this record matches the configured filter. |
| 641 | pub fn matches(&self, record: &Record<'_>) -> bool { |
| 642 | self.filter.matches(record) |
| 643 | } |
| 644 | } |
| 645 | |
| 646 | impl Log for Logger { |
| 647 | fn enabled(&self, metadata: &Metadata<'_>) -> bool { |
| 648 | self.filter.enabled(metadata) |
| 649 | } |
| 650 | |
| 651 | fn log(&self, record: &Record<'_>) { |
| 652 | if self.matches(record) { |
| 653 | // Log records are written to a thread-local buffer before being printed |
| 654 | // to the terminal. We clear these buffers afterwards, but they aren't shrunk |
| 655 | // so will always at least have capacity for the largest log record formatted |
| 656 | // on that thread. |
| 657 | // |
| 658 | // If multiple `Logger`s are used by the same threads then the thread-local |
| 659 | // formatter might have different color support. If this is the case the |
| 660 | // formatter and its buffer are discarded and recreated. |
| 661 | |
| 662 | thread_local! { |
| 663 | static FORMATTER: RefCell<Option<Formatter>> = const { RefCell::new(None) }; |
| 664 | } |
| 665 | |
| 666 | let print = |formatter: &mut Formatter, record: &Record<'_>| { |
| 667 | let _ = |
| 668 | (self.format)(formatter, record).and_then(|_| formatter.print(&self.writer)); |
| 669 | |
| 670 | // Always clear the buffer afterwards |
| 671 | formatter.clear(); |
| 672 | }; |
| 673 | |
| 674 | let printed = FORMATTER |
| 675 | .try_with(|tl_buf| { |
| 676 | if let Ok(mut tl_buf) = tl_buf.try_borrow_mut() { |
| 677 | // There are no active borrows of the buffer |
| 678 | if let Some(ref mut formatter) = *tl_buf { |
| 679 | // We have a previously set formatter |
| 680 | |
| 681 | // Check the buffer style. If it's different from the logger's |
| 682 | // style then drop the buffer and recreate it. |
| 683 | if formatter.write_style() != self.writer.write_style() { |
| 684 | *formatter = Formatter::new(&self.writer); |
| 685 | } |
| 686 | |
| 687 | print(formatter, record); |
| 688 | } else { |
| 689 | // We don't have a previously set formatter |
| 690 | let mut formatter = Formatter::new(&self.writer); |
| 691 | print(&mut formatter, record); |
| 692 | |
| 693 | *tl_buf = Some(formatter); |
| 694 | } |
| 695 | } else { |
| 696 | // There's already an active borrow of the buffer (due to re-entrancy) |
| 697 | print(&mut Formatter::new(&self.writer), record); |
| 698 | } |
| 699 | }) |
| 700 | .is_ok(); |
| 701 | |
| 702 | if !printed { |
| 703 | // The thread-local storage was not available (because its |
| 704 | // destructor has already run). Create a new single-use |
| 705 | // Formatter on the stack for this call. |
| 706 | print(&mut Formatter::new(&self.writer), record); |
| 707 | } |
| 708 | } |
| 709 | } |
| 710 | |
| 711 | fn flush(&self) {} |
| 712 | } |
| 713 | |
| 714 | impl std::fmt::Debug for Logger { |
| 715 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 716 | f&mut DebugStruct<'_, '_>.debug_struct("Logger") |
| 717 | .field(name:"filter", &self.filter) |
| 718 | .finish() |
| 719 | } |
| 720 | } |
| 721 | |
| 722 | /// Set of environment variables to configure from. |
| 723 | /// |
| 724 | /// # Default environment variables |
| 725 | /// |
| 726 | /// By default, the `Env` will read the following environment variables: |
| 727 | /// |
| 728 | /// - `RUST_LOG`: the level filter |
| 729 | /// - `RUST_LOG_STYLE`: whether or not to print styles with records. |
| 730 | /// |
| 731 | /// These sources can be configured using the builder methods on `Env`. |
| 732 | #[derive(Debug)] |
| 733 | pub struct Env<'a> { |
| 734 | filter: Var<'a>, |
| 735 | write_style: Var<'a>, |
| 736 | } |
| 737 | |
| 738 | impl<'a> Env<'a> { |
| 739 | /// Get a default set of environment variables. |
| 740 | pub fn new() -> Self { |
| 741 | Self::default() |
| 742 | } |
| 743 | |
| 744 | /// Specify an environment variable to read the filter from. |
| 745 | pub fn filter<E>(mut self, filter_env: E) -> Self |
| 746 | where |
| 747 | E: Into<Cow<'a, str>>, |
| 748 | { |
| 749 | self.filter = Var::new(filter_env); |
| 750 | |
| 751 | self |
| 752 | } |
| 753 | |
| 754 | /// Specify an environment variable to read the filter from. |
| 755 | /// |
| 756 | /// If the variable is not set, the default value will be used. |
| 757 | pub fn filter_or<E, V>(mut self, filter_env: E, default: V) -> Self |
| 758 | where |
| 759 | E: Into<Cow<'a, str>>, |
| 760 | V: Into<Cow<'a, str>>, |
| 761 | { |
| 762 | self.filter = Var::new_with_default(filter_env, default); |
| 763 | |
| 764 | self |
| 765 | } |
| 766 | |
| 767 | /// Use the default environment variable to read the filter from. |
| 768 | /// |
| 769 | /// If the variable is not set, the default value will be used. |
| 770 | pub fn default_filter_or<V>(mut self, default: V) -> Self |
| 771 | where |
| 772 | V: Into<Cow<'a, str>>, |
| 773 | { |
| 774 | self.filter = Var::new_with_default(DEFAULT_FILTER_ENV, default); |
| 775 | |
| 776 | self |
| 777 | } |
| 778 | |
| 779 | fn get_filter(&self) -> Option<String> { |
| 780 | self.filter.get() |
| 781 | } |
| 782 | |
| 783 | /// Specify an environment variable to read the style from. |
| 784 | pub fn write_style<E>(mut self, write_style_env: E) -> Self |
| 785 | where |
| 786 | E: Into<Cow<'a, str>>, |
| 787 | { |
| 788 | self.write_style = Var::new(write_style_env); |
| 789 | |
| 790 | self |
| 791 | } |
| 792 | |
| 793 | /// Specify an environment variable to read the style from. |
| 794 | /// |
| 795 | /// If the variable is not set, the default value will be used. |
| 796 | pub fn write_style_or<E, V>(mut self, write_style_env: E, default: V) -> Self |
| 797 | where |
| 798 | E: Into<Cow<'a, str>>, |
| 799 | V: Into<Cow<'a, str>>, |
| 800 | { |
| 801 | self.write_style = Var::new_with_default(write_style_env, default); |
| 802 | |
| 803 | self |
| 804 | } |
| 805 | |
| 806 | /// Use the default environment variable to read the style from. |
| 807 | /// |
| 808 | /// If the variable is not set, the default value will be used. |
| 809 | pub fn default_write_style_or<V>(mut self, default: V) -> Self |
| 810 | where |
| 811 | V: Into<Cow<'a, str>>, |
| 812 | { |
| 813 | self.write_style = Var::new_with_default(DEFAULT_WRITE_STYLE_ENV, default); |
| 814 | |
| 815 | self |
| 816 | } |
| 817 | |
| 818 | fn get_write_style(&self) -> Option<String> { |
| 819 | self.write_style.get() |
| 820 | } |
| 821 | } |
| 822 | |
| 823 | impl<'a, T> From<T> for Env<'a> |
| 824 | where |
| 825 | T: Into<Cow<'a, str>>, |
| 826 | { |
| 827 | fn from(filter_env: T) -> Self { |
| 828 | Env::default().filter(filter_env.into()) |
| 829 | } |
| 830 | } |
| 831 | |
| 832 | impl Default for Env<'_> { |
| 833 | fn default() -> Self { |
| 834 | Env { |
| 835 | filter: Var::new(DEFAULT_FILTER_ENV), |
| 836 | write_style: Var::new(DEFAULT_WRITE_STYLE_ENV), |
| 837 | } |
| 838 | } |
| 839 | } |
| 840 | |
| 841 | #[derive(Debug)] |
| 842 | struct Var<'a> { |
| 843 | name: Cow<'a, str>, |
| 844 | default: Option<Cow<'a, str>>, |
| 845 | } |
| 846 | |
| 847 | impl<'a> Var<'a> { |
| 848 | fn new<E>(name: E) -> Self |
| 849 | where |
| 850 | E: Into<Cow<'a, str>>, |
| 851 | { |
| 852 | Var { |
| 853 | name: name.into(), |
| 854 | default: None, |
| 855 | } |
| 856 | } |
| 857 | |
| 858 | fn new_with_default<E, V>(name: E, default: V) -> Self |
| 859 | where |
| 860 | E: Into<Cow<'a, str>>, |
| 861 | V: Into<Cow<'a, str>>, |
| 862 | { |
| 863 | Var { |
| 864 | name: name.into(), |
| 865 | default: Some(default.into()), |
| 866 | } |
| 867 | } |
| 868 | |
| 869 | fn get(&self) -> Option<String> { |
| 870 | env::var(&*self.name) |
| 871 | .ok() |
| 872 | .or_else(|| self.default.clone().map(|v| v.into_owned())) |
| 873 | } |
| 874 | } |
| 875 | |
| 876 | /// Attempts to initialize the global logger with an env logger. |
| 877 | /// |
| 878 | /// This should be called early in the execution of a Rust program. Any log |
| 879 | /// events that occur before initialization will be ignored. |
| 880 | /// |
| 881 | /// # Errors |
| 882 | /// |
| 883 | /// This function will fail if it is called more than once, or if another |
| 884 | /// library has already initialized a global logger. |
| 885 | pub fn try_init() -> Result<(), SetLoggerError> { |
| 886 | try_init_from_env(Env::default()) |
| 887 | } |
| 888 | |
| 889 | /// Initializes the global logger with an env logger. |
| 890 | /// |
| 891 | /// This should be called early in the execution of a Rust program. Any log |
| 892 | /// events that occur before initialization will be ignored. |
| 893 | /// |
| 894 | /// # Panics |
| 895 | /// |
| 896 | /// This function will panic if it is called more than once, or if another |
| 897 | /// library has already initialized a global logger. |
| 898 | pub fn init() { |
| 899 | try_init().expect(msg:"env_logger::init should not be called after logger initialized"); |
| 900 | } |
| 901 | |
| 902 | /// Attempts to initialize the global logger with an env logger from the given |
| 903 | /// environment variables. |
| 904 | /// |
| 905 | /// This should be called early in the execution of a Rust program. Any log |
| 906 | /// events that occur before initialization will be ignored. |
| 907 | /// |
| 908 | /// # Examples |
| 909 | /// |
| 910 | /// Initialise a logger using the `MY_LOG` environment variable for filters |
| 911 | /// and `MY_LOG_STYLE` for writing colors: |
| 912 | /// |
| 913 | /// ``` |
| 914 | /// use env_logger::{Builder, Env}; |
| 915 | /// |
| 916 | /// # fn run() -> Result<(), Box<dyn ::std::error::Error>> { |
| 917 | /// let env = Env::new().filter("MY_LOG").write_style( "MY_LOG_STYLE"); |
| 918 | /// |
| 919 | /// env_logger::try_init_from_env(env)?; |
| 920 | /// |
| 921 | /// Ok(()) |
| 922 | /// # } |
| 923 | /// # run().unwrap(); |
| 924 | /// ``` |
| 925 | /// |
| 926 | /// # Errors |
| 927 | /// |
| 928 | /// This function will fail if it is called more than once, or if another |
| 929 | /// library has already initialized a global logger. |
| 930 | pub fn try_init_from_env<'a, E>(env: E) -> Result<(), SetLoggerError> |
| 931 | where |
| 932 | E: Into<Env<'a>>, |
| 933 | { |
| 934 | let mut builder: Builder = Builder::from_env(env); |
| 935 | |
| 936 | builder.try_init() |
| 937 | } |
| 938 | |
| 939 | /// Initializes the global logger with an env logger from the given environment |
| 940 | /// variables. |
| 941 | /// |
| 942 | /// This should be called early in the execution of a Rust program. Any log |
| 943 | /// events that occur before initialization will be ignored. |
| 944 | /// |
| 945 | /// # Examples |
| 946 | /// |
| 947 | /// Initialise a logger using the `MY_LOG` environment variable for filters |
| 948 | /// and `MY_LOG_STYLE` for writing colors: |
| 949 | /// |
| 950 | /// ``` |
| 951 | /// use env_logger::{Builder, Env}; |
| 952 | /// |
| 953 | /// let env = Env::new().filter("MY_LOG").write_style( "MY_LOG_STYLE"); |
| 954 | /// |
| 955 | /// env_logger::init_from_env(env); |
| 956 | /// ``` |
| 957 | /// |
| 958 | /// # Panics |
| 959 | /// |
| 960 | /// This function will panic if it is called more than once, or if another |
| 961 | /// library has already initialized a global logger. |
| 962 | pub fn init_from_env<'a, E>(env: E) |
| 963 | where |
| 964 | E: Into<Env<'a>>, |
| 965 | { |
| 966 | try_init_from_env(env) |
| 967 | .expect(msg:"env_logger::init_from_env should not be called after logger initialized"); |
| 968 | } |
| 969 | |
| 970 | /// Create a new builder with the default environment variables. |
| 971 | /// |
| 972 | /// The builder can be configured before being initialized. |
| 973 | /// This is a convenient way of calling [`Builder::from_default_env`]. |
| 974 | /// |
| 975 | /// [`Builder::from_default_env`]: struct.Builder.html#method.from_default_env |
| 976 | pub fn builder() -> Builder { |
| 977 | Builder::from_default_env() |
| 978 | } |
| 979 | |
| 980 | /// Create a builder from the given environment variables. |
| 981 | /// |
| 982 | /// The builder can be configured before being initialized. |
| 983 | #[deprecated( |
| 984 | since = "0.8.0", |
| 985 | note = "Prefer `env_logger::Builder::from_env()` instead." |
| 986 | )] |
| 987 | pub fn from_env<'a, E>(env: E) -> Builder |
| 988 | where |
| 989 | E: Into<Env<'a>>, |
| 990 | { |
| 991 | Builder::from_env(env) |
| 992 | } |
| 993 | |
| 994 | #[cfg(test)] |
| 995 | mod tests { |
| 996 | use super::*; |
| 997 | |
| 998 | #[test] |
| 999 | fn env_get_filter_reads_from_var_if_set() { |
| 1000 | env::set_var("env_get_filter_reads_from_var_if_set", "from var"); |
| 1001 | |
| 1002 | let env = Env::new().filter_or("env_get_filter_reads_from_var_if_set", "from default"); |
| 1003 | |
| 1004 | assert_eq!(Some("from var".to_owned()), env.get_filter()); |
| 1005 | } |
| 1006 | |
| 1007 | #[test] |
| 1008 | fn env_get_filter_reads_from_default_if_var_not_set() { |
| 1009 | env::remove_var("env_get_filter_reads_from_default_if_var_not_set"); |
| 1010 | |
| 1011 | let env = Env::new().filter_or( |
| 1012 | "env_get_filter_reads_from_default_if_var_not_set", |
| 1013 | "from default", |
| 1014 | ); |
| 1015 | |
| 1016 | assert_eq!(Some("from default".to_owned()), env.get_filter()); |
| 1017 | } |
| 1018 | |
| 1019 | #[test] |
| 1020 | fn env_get_write_style_reads_from_var_if_set() { |
| 1021 | env::set_var("env_get_write_style_reads_from_var_if_set", "from var"); |
| 1022 | |
| 1023 | let env = |
| 1024 | Env::new().write_style_or("env_get_write_style_reads_from_var_if_set", "from default"); |
| 1025 | |
| 1026 | assert_eq!(Some("from var".to_owned()), env.get_write_style()); |
| 1027 | } |
| 1028 | |
| 1029 | #[test] |
| 1030 | fn env_get_write_style_reads_from_default_if_var_not_set() { |
| 1031 | env::remove_var("env_get_write_style_reads_from_default_if_var_not_set"); |
| 1032 | |
| 1033 | let env = Env::new().write_style_or( |
| 1034 | "env_get_write_style_reads_from_default_if_var_not_set", |
| 1035 | "from default", |
| 1036 | ); |
| 1037 | |
| 1038 | assert_eq!(Some("from default".to_owned()), env.get_write_style()); |
| 1039 | } |
| 1040 | |
| 1041 | #[test] |
| 1042 | fn builder_parse_env_overrides_existing_filters() { |
| 1043 | env::set_var( |
| 1044 | "builder_parse_default_env_overrides_existing_filters", |
| 1045 | "debug", |
| 1046 | ); |
| 1047 | let env = Env::new().filter("builder_parse_default_env_overrides_existing_filters"); |
| 1048 | |
| 1049 | let mut builder = Builder::new(); |
| 1050 | builder.filter_level(LevelFilter::Trace); |
| 1051 | // Overrides global level to debug |
| 1052 | builder.parse_env(env); |
| 1053 | |
| 1054 | assert_eq!(builder.filter.build().filter(), LevelFilter::Debug); |
| 1055 | } |
| 1056 | } |
| 1057 |
Definitions
- Builder
- filter
- writer
- format
- built
- new
- from_env
- parse_env
- from_default_env
- parse_default_env
- format
- default_format
- format_level
- format_file
- format_line_number
- format_source_path
- format_module_path
- format_target
- format_indent
- format_timestamp
- format_timestamp_secs
- format_timestamp_millis
- format_timestamp_micros
- format_timestamp_nanos
- format_suffix
- filter_module
- filter_level
- filter
- parse_filters
- target
- write_style
- parse_write_style
- is_test
- try_init
- init
- build
- fmt
- Logger
- writer
- filter
- format
- from_env
- from_default_env
- filter
- matches
- enabled
- log
- flush
- fmt
- Env
- filter
- write_style
- new
- filter
- filter_or
- default_filter_or
- get_filter
- write_style
- write_style_or
- default_write_style_or
- get_write_style
- from
- default
- Var
- name
- default
- new
- new_with_default
- get
- try_init
- init
- try_init_from_env
- init_from_env
- builder
Learn Rust with the experts
Find out more
