(index<- )        ./liblog/directive.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  use std::ascii::StrAsciiExt;
  12  use std::cmp;
  13  
  14  #[deriving(Show, Clone)]
  15  pub struct LogDirective {
  16      pub name: Option<~str>,
  17      pub level: u32,
  18  }
  19  
  20  pub static LOG_LEVEL_NAMES: [&'static str, ..4] = ["ERROR", "WARN", "INFO",
  21                                                 "DEBUG"];
  22  
  23  /// Parse an individual log level that is either a number or a symbolic log level
  24  fn parse_log_level(level: &str) -> Option<u32> {
  25      from_str::<u32>(level).or_else(|| {
  26          let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
  27          pos.map(|p| p as u32 + 1)
  28      }).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
  29  }
  30  
  31  /// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
  32  /// and return a vector with log directives.
  33  ///
  34  /// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
  35  /// std::).  Also supports string log levels of error, warn, info, and debug
  36  pub fn parse_logging_spec(spec: &str) -> Vec<LogDirective> {
  37      let mut dirs = Vec::new();
  38      for s in spec.split(',') {
  39          if s.len() == 0 { continue }
  40          let mut parts = s.split('=');
  41          let (log_level, name) = match (parts.next(), parts.next(), parts.next()) {
  42              (Some(part0), None, None) => {
  43                  // if the single argument is a log-level string or number,
  44                  // treat that as a global fallback
  45                  match parse_log_level(part0) {
  46                      Some(num) => (num, None),
  47                      None => (::MAX_LOG_LEVEL, Some(part0)),
  48                  }
  49              }
  50              (Some(part0), Some(part1), None) => {
  51                  match parse_log_level(part1) {
  52                      Some(num) => (num, Some(part0)),
  53                      _ => {
  54                          println!("warning: invalid logging spec '{}', \
  55                                   ignoring it", part1);
  56                          continue
  57                      }
  58                  }
  59              },
  60              _ => {
  61                  println!("warning: invalid logging spec '{}', \
  62                           ignoring it", s);
  63                  continue
  64              }
  65          };
  66          dirs.push(LogDirective {
  67              name: name.map(|s| s.to_owned()),
  68              level: log_level,
  69          });
  70      }
  71      return dirs;
  72  }
  73  
  74  #[cfg(test)]
  75  mod tests {
  76      use super::parse_logging_spec;
  77  
  78      #[test]
  79      fn parse_logging_spec_valid() {
  80          let dirs = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
  81          let dirs = dirs.as_slice();
  82          assert_eq!(dirs.len(), 3);
  83          assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned()));
  84          assert_eq!(dirs[0].level, 1);
  85  
  86          assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned()));
  87          assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);
  88  
  89          assert_eq!(dirs[2].name, Some("crate2".to_owned()));
  90          assert_eq!(dirs[2].level, 4);
  91      }
  92  
  93      #[test]
  94      fn parse_logging_spec_invalid_crate() {
  95          // test parse_logging_spec with multiple = in specification
  96          let dirs = parse_logging_spec("crate1::mod1=1=2,crate2=4");
  97          let dirs = dirs.as_slice();
  98          assert_eq!(dirs.len(), 1);
  99          assert_eq!(dirs[0].name, Some("crate2".to_owned()));
 100          assert_eq!(dirs[0].level, 4);
 101      }
 102  
 103      #[test]
 104      fn parse_logging_spec_invalid_log_level() {
 105          // test parse_logging_spec with 'noNumber' as log level
 106          let dirs = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
 107          let dirs = dirs.as_slice();
 108          assert_eq!(dirs.len(), 1);
 109          assert_eq!(dirs[0].name, Some("crate2".to_owned()));
 110          assert_eq!(dirs[0].level, 4);
 111      }
 112  
 113      #[test]
 114      fn parse_logging_spec_string_log_level() {
 115          // test parse_logging_spec with 'warn' as log level
 116          let dirs = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
 117          let dirs = dirs.as_slice();
 118          assert_eq!(dirs.len(), 1);
 119          assert_eq!(dirs[0].name, Some("crate2".to_owned()));
 120          assert_eq!(dirs[0].level, ::WARN);
 121      }
 122  
 123      #[test]
 124      fn parse_logging_spec_global() {
 125          // test parse_logging_spec with no crate
 126          let dirs = parse_logging_spec("warn,crate2=4");
 127          let dirs = dirs.as_slice();
 128          assert_eq!(dirs.len(), 2);
 129          assert_eq!(dirs[0].name, None);
 130          assert_eq!(dirs[0].level, 2);
 131          assert_eq!(dirs[1].name, Some("crate2".to_owned()));
 132          assert_eq!(dirs[1].level, 4);
 133      }
 134  }