(index<- )        ./liblog/lib.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  /*!
  12  
  13  Utilities for program-wide and customizable logging
  14  
  15  ## Example
  16  
  17  ```
  18  #![feature(phase)]
  19  #[phase(syntax, link)] extern crate log;
  20  
  21  fn main() {
  22      debug!("this is a debug {}", "message");
  23      error!("this is printed by default");
  24  
  25      if log_enabled!(log::INFO) {
  26          let x = 3 * 4; // expensive computation
  27          info!("the answer was: {}", x);
  28      }
  29  }
  30  ```
  31  
  32  ## Logging Macros
  33  
  34  There are five macros that the logging subsystem uses:
  35  
  36  * `log!(level, ...)` - the generic logging macro, takes a level as a u32 and any
  37                         related `format!` arguments
  38  * `debug!(...)` - a macro hard-wired to the log level of `DEBUG`
  39  * `info!(...)` - a macro hard-wired to the log level of `INFO`
  40  * `warn!(...)` - a macro hard-wired to the log level of `WARN`
  41  * `error!(...)` - a macro hard-wired to the log level of `ERROR`
  42  
  43  All of these macros use the same style of syntax as the `format!` syntax
  44  extension. Details about the syntax can be found in the documentation of
  45  `std::fmt` along with the Rust tutorial/manual.
  46  
  47  If you want to check at runtime if a given logging level is enabled (e.g. if the
  48  information you would want to log is expensive to produce), you can use the
  49  following macro:
  50  
  51  * `log_enabled!(level)` - returns true if logging of the given level is enabled
  52  
  53  ## Enabling logging
  54  
  55  Log levels are controlled on a per-module basis, and by default all logging is
  56  disabled except for `error!` (a log level of 1). Logging is controlled via the
  57  `RUST_LOG` environment variable. The value of this environment variable is a
  58  comma-separated list of logging directives. A logging directive is of the form:
  59  
  60  ```notrust
  61  path::to::module=log_level
  62  ```
  63  
  64  The path to the module is rooted in the name of the crate it was compiled for,
  65  so if your program is contained in a file `hello.rs`, for example, to turn on
  66  logging for this file you would use a value of `RUST_LOG=hello`.
  67  Furthermore, this path is a prefix-search, so all modules nested in the
  68  specified module will also have logging enabled.
  69  
  70  The actual `log_level` is optional to specify. If omitted, all logging will be
  71  enabled. If specified, the it must be either a numeric in the range of 1-255, or
  72  it must be one of the strings `debug`, `error`, `info`, or `warn`. If a numeric
  73  is specified, then all logging less than or equal to that numeral is enabled.
  74  For example, if logging level 3 is active, error, warn, and info logs will be
  75  printed, but debug will be omitted.
  76  
  77  As the log level for a module is optional, the module to enable logging for is
  78  also optional. If only a `log_level` is provided, then the global log level for
  79  all modules is set to this value.
  80  
  81  Some examples of valid values of `RUST_LOG` are:
  82  
  83  ```notrust
  84  hello                // turns on all logging for the 'hello' module
  85  info                 // turns on all info logging
  86  hello=debug          // turns on debug logging for 'hello'
  87  hello=3              // turns on info logging for 'hello'
  88  hello,std::option    // turns on hello, and std's option logging
  89  error,hello=warn     // turn on global error logging and also warn for hello
  90  ```
  91  
  92  ## Performance and Side Effects
  93  
  94  Each of these macros will expand to code similar to:
  95  
  96  ```rust,ignore
  97  if log_level <= my_module_log_level() {
  98      ::log::log(log_level, format!(...));
  99  }
 100  ```
 101  
 102  What this means is that each of these macros are very cheap at runtime if
 103  they're turned off (just a load and an integer comparison). This also means that
 104  if logging is disabled, none of the components of the log will be executed.
 105  
 106  */
 107  
 108  #![crate_id = "log#0.11-pre"]
 109  #![license = "MIT/ASL2"]
 110  #![crate_type = "rlib"]
 111  #![crate_type = "dylib"]
 112  #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
 113         html_favicon_url = "http://www.rust-lang.org/favicon.ico",
 114         html_root_url = "http://static.rust-lang.org/doc/master")]
 115  
 116  #![feature(macro_rules)]
 117  #![deny(missing_doc, deprecated_owned_vector)]
 118  
 119  extern crate sync;
 120  
 121  use std::cast;
 122  use std::fmt;
 123  use std::io::LineBufferedWriter;
 124  use std::io;
 125  use std::os;
 126  use std::rt;
 127  use std::slice;
 128  
 129  use sync::one::{Once, ONCE_INIT};
 130  
 131  use directive::LOG_LEVEL_NAMES;
 132  
 133  pub mod macros;
 134  mod directive;
 135  
 136  /// Maximum logging level of a module that can be specified. Common logging
 137  /// levels are found in the DEBUG/INFO/WARN/ERROR constants.
 138  pub static MAX_LOG_LEVEL: u32 = 255;
 139  
 140  /// The default logging level of a crate if no other is specified.
 141  static DEFAULT_LOG_LEVEL: u32 = 1;
 142  
 143  /// An unsafe constant that is the maximum logging level of any module
 144  /// specified. This is the first line of defense to determining whether a
 145  /// logging statement should be run.
 146  static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL;
 147  
 148  static mut DIRECTIVES: *Vec<directive::LogDirective> =
 149      0 as *Vec<directive::LogDirective>;
 150  
 151  /// Debug log level
 152  pub static DEBUG: u32 = 4;
 153  /// Info log level
 154  pub static INFO: u32 = 3;
 155  /// Warn log level
 156  pub static WARN: u32 = 2;
 157  /// Error log level
 158  pub static ERROR: u32 = 1;
 159  
 160  local_data_key!(local_logger: Box<Logger:Send>)
 161  
 162  /// A trait used to represent an interface to a task-local logger. Each task
 163  /// can have its own custom logger which can respond to logging messages
 164  /// however it likes.
 165  pub trait Logger {
 166      /// Logs a single message described by the `record`.
 167      fn log(&mut self, record: &LogRecord);
 168  }
 169  
 170  struct DefaultLogger {
 171      handle: LineBufferedWriter<io::stdio::StdWriter>,
 172  }
 173  
 174  /// Wraps the log level with fmt implementations.
 175  #[deriving(Eq, Ord)]
 176  pub struct LogLevel(pub u32);
 177  
 178  impl fmt::Show for LogLevel {
 179      fn fmt(&self, fmt&mut fmt::Formatter) -> fmt::Result {
 180          let LogLevel(level) = *self;
 181          match LOG_LEVEL_NAMES.get(level as uint - 1) {
 182              Some(name) => name.fmt(fmt),
 183              None => level.fmt(fmt)
 184          }
 185      }
 186  }
 187  
 188  impl fmt::Signed for LogLevel {
 189      fn fmt(&self, fmt&mut fmt::Formatter) -> fmt::Result {
 190          let LogLevel(level) = *self;
 191          write!(fmt.buf, "{}", level)
 192      }
 193  }
 194  
 195  impl Logger for DefaultLogger {
 196      fn log(&mut self, record&LogRecord) {
 197          match writeln!(&mut self.handle,
 198                         "{}:{}{}",
 199                         record.level,
 200                         record.module_path,
 201                         record.args) {
 202              Err(e) => fail!("failed to log: {}", e),
 203              Ok(()) => {}
 204          }
 205      }
 206  }
 207  
 208  impl Drop for DefaultLogger {
 209      fn drop(&mut self) {
 210          // FIXME(#12628): is failure the right thing to do?
 211          match self.handle.flush() {
 212              Err(e) => fail!("failed to flush a logger: {}", e),
 213              Ok(()) => {}
 214          }
 215      }
 216  }
 217  
 218  /// This function is called directly by the compiler when using the logging
 219  /// macros. This function does not take into account whether the log level
 220  /// specified is active or not, it will always log something if this method is
 221  /// called.
 222  ///
 223  /// It is not recommended to call this function directly, rather it should be
 224  /// invoked through the logging family of macros.
 225  #[doc(hidden)]
 226  pub fn log(level: u32, loc: &'static LogLocationargs: &fmt::Arguments{
 227      // Completely remove the local logger from TLS in case anyone attempts to
 228      // frob the slot while we're doing the logging. This will destroy any logger
 229      // set during logging.
 230      let mut logger = local_logger.replace(None).unwrap_or_else(|| {
 231          box DefaultLogger { handle: io::stderr() } as Box<Logger:Send>
 232      });
 233      logger.log(&LogRecord {
 234          level: LogLevel(level),
 235          args: args,
 236          file: loc.file,
 237          module_path: loc.module_path,
 238          line: loc.line,
 239      });
 240      local_logger.replace(Some(logger));
 241  }
 242  
 243  /// Getter for the global log level. This is a function so that it can be called
 244  /// safely
 245  #[doc(hidden)]
 246  #[inline(always)]
 247  pub fn log_level() -> u32 { unsafe { LOG_LEVEL } }
 248  
 249  /// Replaces the task-local logger with the specified logger, returning the old
 250  /// logger.
 251  pub fn set_logger(loggerBox<Logger:Send>) -> Option<Box<Logger:Send>> {
 252      local_logger.replace(Some(logger))
 253  }
 254  
 255  /// A LogRecord is created by the logging macros, and passed as the only
 256  /// argument to Loggers.
 257  #[deriving(Show)]
 258  pub struct LogRecord<'a> {
 259  
 260      /// The module path of where the LogRecord originated.
 261      pub module_path: &'a str,
 262  
 263      /// The LogLevel of this record.
 264      pub level: LogLevel,
 265  
 266      /// The arguments from the log line.
 267      pub args: &'a fmt::Arguments<'a>,
 268  
 269      /// The file of where the LogRecord originated.
 270      pub file: &'a str,
 271  
 272      /// The line number of where the LogRecord originated.
 273      pub line: uint,
 274  }
 275  
 276  #[doc(hidden)]
 277  pub struct LogLocation {
 278      pub module_path: &'static str,
 279      pub file: &'static str,
 280      pub line: uint,
 281  }
 282  
 283  /// Tests whether a given module's name is enabled for a particular level of
 284  /// logging. This is the second layer of defense about determining whether a
 285  /// module's log statement should be emitted or not.
 286  #[doc(hidden)]
 287  pub fn mod_enabled(level: u32, module: &str) -> bool {
 288      static mut INIT: Once = ONCE_INIT;
 289      unsafe { INIT.doit(init); }
 290  
 291      // It's possible for many threads are in this function, only one of them
 292      // will peform the global initialization, but all of them will need to check
 293      // again to whether they should really be here or not. Hence, despite this
 294      // check being expanded manually in the logging macro, this function checks
 295      // the log level again.
 296      if level > unsafe { LOG_LEVEL } { return false }
 297  
 298      // This assertion should never get tripped unless we're in an at_exit
 299      // handler after logging has been torn down and a logging attempt was made.
 300      assert!(unsafe { !DIRECTIVES.is_null() });
 301  
 302      enabled(level, module, unsafe { (*DIRECTIVES).iter() })
 303  }
 304  
 305  fn enabled(level: u32, module: &str,
 306             iterslice::Items<directive::LogDirective>) -> bool {
 307      // Search for the longest match, the vector is assumed to be pre-sorted.
 308      for directive in iter.rev() {
 309          match directive.name {
 310              Some(ref name) if !module.starts_with(*name) => {},
 311              Some(..) | None => {
 312                  return level <= directive.level
 313              }
 314          }
 315      }
 316      level <= DEFAULT_LOG_LEVEL
 317  }
 318  
 319  /// Initialize logging for the current process.
 320  ///
 321  /// This is not threadsafe at all, so initialization os performed through a
 322  /// `Once` primitive (and this function is called from that primitive).
 323  fn init() {
 324      let mut directives = match os::getenv("RUST_LOG") {
 325          Some(spec) => directive::parse_logging_spec(spec),
 326          None => Vec::new(),
 327      };
 328  
 329      // Sort the provided directives by length of their name, this allows a
 330      // little more efficient lookup at runtime.
 331      directives.sort_by(|a, b| {
 332          let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0);
 333          let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0);
 334          alen.cmp(&blen)
 335      });
 336  
 337      let max_level = {
 338          let max = directives.iter().max_by(|d| d.level);
 339          max.map(|d| d.level).unwrap_or(DEFAULT_LOG_LEVEL)
 340      };
 341  
 342      unsafe {
 343          LOG_LEVEL = max_level;
 344  
 345          assert!(DIRECTIVES.is_null());
 346          DIRECTIVES = cast::transmute(box directives);
 347  
 348          // Schedule the cleanup for this global for when the runtime exits.
 349          rt::at_exit(proc() {
 350              assert!(!DIRECTIVES.is_null());
 351              let _directivesBox<Vec<directive::LogDirective>> =
 352                  cast::transmute(DIRECTIVES);
 353              DIRECTIVES = 0 as *Vec<directive::LogDirective>;
 354          });
 355      }
 356  }
 357  
 358  #[cfg(test)]
 359  mod tests {
 360      use super::enabled;
 361      use directive::LogDirective;
 362  
 363      #[test]
 364      fn match_full_path() {
 365          let dirs = [LogDirective { name: Some("crate2".to_owned()), level: 3 },
 366                      LogDirective { name: Some("crate1::mod1".to_owned()), level: 2 }];
 367          assert!(enabled(2, "crate1::mod1", dirs.iter()));
 368          assert!(!enabled(3, "crate1::mod1", dirs.iter()));
 369          assert!(enabled(3, "crate2", dirs.iter()));
 370          assert!(!enabled(4, "crate2", dirs.iter()));
 371      }
 372  
 373      #[test]
 374      fn no_match() {
 375          let dirs = [LogDirective { name: Some("crate2".to_owned()), level: 3 },
 376                      LogDirective { name: Some("crate1::mod1".to_owned()), level: 2 }];
 377          assert!(!enabled(2, "crate3", dirs.iter()));
 378      }
 379  
 380      #[test]
 381      fn match_beginning() {
 382          let dirs = [LogDirective { name: Some("crate2".to_owned()), level: 3 },
 383                      LogDirective { name: Some("crate1::mod1".to_owned()), level: 2 }];
 384          assert!(enabled(3, "crate2::mod1", dirs.iter()));
 385      }
 386  
 387      #[test]
 388      fn match_beginning_longest_match() {
 389          let dirs = [LogDirective { name: Some("crate2".to_owned()), level: 3 },
 390                      LogDirective { name: Some("crate2::mod".to_owned()), level: 4 },
 391                      LogDirective { name: Some("crate1::mod1".to_owned()), level: 2 }];
 392          assert!(enabled(4, "crate2::mod1", dirs.iter()));
 393          assert!(!enabled(4, "crate2", dirs.iter()));
 394      }
 395  
 396      #[test]
 397      fn match_default() {
 398          let dirs = [LogDirective { name: None, level: 3 },
 399                      LogDirective { name: Some("crate1::mod1".to_owned()), level: 2 }];
 400          assert!(enabled(2, "crate1::mod1", dirs.iter()));
 401          assert!(enabled(3, "crate2::mod2", dirs.iter()));
 402      }
 403  
 404      #[test]
 405      fn zero_level() {
 406          let dirs = [LogDirective { name: None, level: 3 },
 407                      LogDirective { name: Some("crate1::mod1".to_owned()), level: 0 }];
 408          assert!(!enabled(1, "crate1::mod1", dirs.iter()));
 409          assert!(enabled(3, "crate2::mod2", dirs.iter()));
 410      }
 411  }


liblog/lib.rs:257:18-257:18 -struct- definition:
pub struct LogRecord<'a> {
    /// The module path of where the LogRecord originated.
    pub module_path: &'a str,
references:- 5
195: impl Logger for DefaultLogger {
196:     fn log(&mut self, record: &LogRecord) {
197:         match writeln!(&mut self.handle,
--
256: /// argument to Loggers.
258: pub struct LogRecord<'a> {


liblog/lib.rs:164:22-164:22 -trait- definition:
/// however it likes.
pub trait Logger {
    /// Logs a single message described by the `record`.
references:- 5
160: local_data_key!(local_logger: Box<Logger:Send>)
--
250: /// logger.
251: pub fn set_logger(logger: Box<Logger:Send>) -> Option<Box<Logger:Send>> {
252:     local_logger.replace(Some(logger))


liblog/lib.rs:169:1-169:1 -struct- definition:
struct DefaultLogger {
    handle: LineBufferedWriter<io::stdio::StdWriter>,
}
references:- 3
230:     let mut logger = local_logger.replace(None).unwrap_or_else(|| {
231:         box DefaultLogger { handle: io::stderr() } as Box<Logger:Send>
232:     });


liblog/lib.rs:175:21-175:21 -struct- definition:
pub struct LogLevel(pub u32);
impl fmt::Show for LogLevel {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
references:- 11
178: impl fmt::Show for LogLevel {
179:     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
--
188: impl fmt::Signed for LogLevel {
189:     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
--
263:     /// The LogLevel of this record.
264:     pub level: LogLevel,