(index<- )        ./libstd/rt/logging.rs

   1  // Copyright 2013 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 fmt;
  12  use from_str::from_str;
  13  use libc::exit;
  14  use option::{Some, None, Option};
  15  use rt::crate_map::{ModEntry, CrateMap, iter_crate_map, get_crate_map};
  16  use str::StrSlice;
  17  use u32;
  18  use vec::ImmutableVector;
  19  #[cfg(test)] use cast::transmute;
  20  
  21  struct LogDirective {
  22      name: Option<~str>,
  23      level: u32
  24  }
  25  
  26  static MAX_LOG_LEVEL: u32 = 255;
  27  static DEFAULT_LOG_LEVEL: u32 = 1;
  28  static log_level_names : &'static[&'static str] = &'static["error", "warn", "info", "debug"];
  29  
  30  /// Parse an individual log level that is either a number or a symbolic log level
  31  fn parse_log_level(level&str) -> Option<u32> {
  32      let num = from_str::<u32>(level);
  33      let mut log_level;
  34      match num {
  35          Some(num) => {
  36              if num < MAX_LOG_LEVEL {
  37                  log_level = Some(num);
  38              } else {
  39                  log_level = Some(MAX_LOG_LEVEL);
  40              }
  41          }
  42          _ => {
  43              let position = log_level_names.iter().position(|&name| name == level);
  44              match position {
  45                  Some(position) => {
  46                      log_level = Some(u32::min(MAX_LOG_LEVEL, (position + 1) as u32))
  47                  },
  48                  _ => {
  49                      log_level = None;
  50                  }
  51              }
  52          }
  53      }
  54      log_level
  55  }
  56  
  57  /// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
  58  /// and return a vector with log directives.
  59  /// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in std::).
  60  /// Also supports string log levels of error, warn, info, and debug
  61  fn parse_logging_spec(spec~str) -> ~[LogDirective]{
  62      let mut dirs = ~[];
  63      for s in spec.split_iter(',') {
  64          let parts~[&str] = s.split_iter('=').collect();
  65          let mut log_level;
  66          let mut name = Some(parts[0].to_owned());
  67          match parts.len() {
  68              1 => {
  69                  //if the single argument is a log-level string or number,
  70                  //treat that as a global fallback
  71                  let possible_log_level = parse_log_level(parts[0]);
  72                  match possible_log_level {
  73                      Some(num) => {
  74                          name = None;
  75                          log_level = num;
  76                      },
  77                      _ => {
  78                          log_level = MAX_LOG_LEVEL
  79                      }
  80                  }
  81              }
  82              2 => {
  83                  let possible_log_level = parse_log_level(parts[1]);
  84                  match possible_log_level {
  85                      Some(num) => {
  86                          log_level = num;
  87                      },
  88                      _ => {
  89                          rterrln!("warning: invalid logging spec '{}', \
  90                                    ignoring it", parts[1]);
  91                          continue
  92                      }
  93                  }
  94              },
  95              _ => {
  96                  rterrln!("warning: invalid logging spec '{}', \
  97                            ignoring it", s);
  98                  continue
  99              }
 100          }
 101          let dir = LogDirective {name: name, level: log_level};
 102          dirs.push(dir);
 103      }
 104      return dirs;
 105  }
 106  
 107  /// Set the log level of an entry in the crate map depending on the vector
 108  /// of log directives
 109  fn update_entry(dirs&[LogDirective], entry&ModEntry) -> u32 {
 110      let mut new_lvlu32 = DEFAULT_LOG_LEVEL;
 111      let mut longest_match = -1i;
 112      for dir in dirs.iter() {
 113          match dir.name {
 114              None => {
 115                  if longest_match == -1 {
 116                      longest_match = 0;
 117                      new_lvl = dir.level;
 118                  }
 119              }
 120              Some(ref dir_name) => {
 121                  let name = entry.name;
 122                  let len = dir_name.len() as int;
 123                  if name.starts_with(*dir_name) &&
 124                      len >= longest_match {
 125                      longest_match = len;
 126                      new_lvl = dir.level;
 127                  }
 128              }
 129          };
 130      }
 131      unsafe { *entry.log_level = new_lvl; }
 132      if longest_match >= 0 { return 1; } else { return 0; }
 133  }
 134  
 135  #[fixed_stack_segment] #[inline(never)]
 136  /// Set log level for every entry in crate_map according to the sepecification
 137  /// in settings
 138  fn update_log_settings(crate_map&CrateMap, settings~str) {
 139      let mut dirs = ~[];
 140      if settings.len() > 0 {
 141          if settings == ~"::help" || settings == ~"?" {
 142              rterrln!("\nCrate log map:\n");
 143              do iter_crate_map(crate_map) |entry| {
 144                  rterrln!({}", entry.name);
 145              }
 146              unsafe { exit(1); }
 147          }
 148          dirs = parse_logging_spec(settings);
 149      }
 150  
 151      let mut n_matchesu32 = 0;
 152      do iter_crate_map(crate_map) |entry| {
 153          let m = update_entry(dirs, entry);
 154          n_matches += m;
 155      }
 156  
 157      if n_matches < (dirs.len() as u32) {
 158          rterrln!("warning: got {} RUST_LOG specs but only matched\n\
 159                    {} of them. You may have mistyped a RUST_LOG spec. \n\
 160                    Use RUST_LOG=::help to see the list of crates and modules.\n",
 161                   dirs.len(), n_matches);
 162      }
 163  }
 164  
 165  pub trait Logger {
 166      fn log(&mut self, args: &fmt::Arguments);
 167  }
 168  
 169  pub struct StdErrLogger;
 170  
 171  impl Logger for StdErrLogger {
 172      fn log(&mut self, args&fmt::Arguments) {
 173          // FIXME(#6846): this should not call the blocking version of println,
 174          //               or at least the default loggers for tasks shouldn't do
 175          //               that
 176          ::rt::util::dumb_println(args);
 177      }
 178  }
 179  
 180  /// Configure logging by traversing the crate map and setting the
 181  /// per-module global logging flags based on the logging spec
 182  pub fn init() {
 183      use os;
 184  
 185      let log_spec = os::getenv("RUST_LOG");
 186      match get_crate_map() {
 187          Some(crate_map) => {
 188              match log_spec {
 189                  Some(spec) => {
 190                      update_log_settings(crate_map, spec);
 191                  }
 192                  None => {
 193                      update_log_settings(crate_map, ~"");
 194                  }
 195              }
 196          },
 197          _ => {
 198              match log_spec {
 199                  Some(_) => {
 200                      rterrln!("warning: RUST_LOG set, but no crate map found.");
 201                  },
 202                  None => {}
 203              }
 204          }
 205      }
 206  }
 207  
 208  // Tests for parse_logging_spec()
 209  #[test]
 210  fn parse_logging_spec_valid() {
 211      let dirs = parse_logging_spec(~"crate1::mod1=1,crate1::mod2,crate2=4");
 212      assert_eq!(dirs.len(), 3);
 213      assert!(dirs[0].name == Some(~"crate1::mod1"));
 214      assert_eq!(dirs[0].level, 1);
 215  
 216      assert!(dirs[1].name == Some(~"crate1::mod2"));
 217      assert_eq!(dirs[1].level, MAX_LOG_LEVEL);
 218  
 219      assert!(dirs[2].name == Some(~"crate2"));
 220      assert_eq!(dirs[2].level, 4);
 221  }
 222  
 223  #[test]
 224  fn parse_logging_spec_invalid_crate() {
 225      // test parse_logging_spec with multiple = in specification
 226      let dirs = parse_logging_spec(~"crate1::mod1=1=2,crate2=4");
 227      assert_eq!(dirs.len(), 1);
 228      assert!(dirs[0].name == Some(~"crate2"));
 229      assert_eq!(dirs[0].level, 4);
 230  }
 231  
 232  #[test]
 233  fn parse_logging_spec_invalid_log_level() {
 234      // test parse_logging_spec with 'noNumber' as log level
 235      let dirs = parse_logging_spec(~"crate1::mod1=noNumber,crate2=4");
 236      assert_eq!(dirs.len(), 1);
 237      assert!(dirs[0].name == Some(~"crate2"));
 238      assert_eq!(dirs[0].level, 4);
 239  }
 240  
 241  #[test]
 242  fn parse_logging_spec_string_log_level() {
 243      // test parse_logging_spec with 'warn' as log level
 244      let dirs = parse_logging_spec(~"crate1::mod1=wrong,crate2=warn");
 245      assert_eq!(dirs.len(), 1);
 246      assert!(dirs[0].name == Some(~"crate2"));
 247      assert_eq!(dirs[0].level, 2);
 248  }
 249  
 250  #[test]
 251  fn parse_logging_spec_global() {
 252      // test parse_logging_spec with no crate
 253      let dirs = parse_logging_spec(~"warn,crate2=4");
 254      assert_eq!(dirs.len(), 2);
 255      assert!(dirs[0].name == None);
 256      assert_eq!(dirs[0].level, 2);
 257      assert!(dirs[1].name == Some(~"crate2"));
 258      assert_eq!(dirs[1].level, 4);
 259  }
 260  
 261  // Tests for update_entry
 262  #[test]
 263  fn update_entry_match_full_path() {
 264      let dirs = ~[LogDirective {name: Some(~"crate1::mod1"), level: 2 },
 265                   LogDirective {name: Some(~"crate2"), level: 3}];
 266      let level = &mut 0;
 267      unsafe {
 268          let entry= &ModEntry {name:"crate1::mod1", log_level: level};
 269          let m = update_entry(dirs, transmute(entry));
 270          assert!(*entry.log_level == 2);
 271          assert!(m == 1);
 272      }
 273  }
 274  
 275  #[test]
 276  fn update_entry_no_match() {
 277      let dirs = ~[LogDirective {name: Some(~"crate1::mod1"), level: 2 },
 278                   LogDirective {name: Some(~"crate2"), level: 3}];
 279      let level = &mut 0;
 280      unsafe {
 281          let entry= &ModEntry {name: "crate3::mod1", log_level: level};
 282          let m = update_entry(dirs, transmute(entry));
 283          assert!(*entry.log_level == DEFAULT_LOG_LEVEL);
 284          assert!(m == 0);
 285      }
 286  }
 287  
 288  #[test]
 289  fn update_entry_match_beginning() {
 290      let dirs = ~[LogDirective {name: Some(~"crate1::mod1"), level: 2 },
 291                   LogDirective {name: Some(~"crate2"), level: 3}];
 292      let level = &mut 0;
 293      unsafe {
 294          let entry= &ModEntry {name: "crate2::mod1", log_level: level};
 295          let m = update_entry(dirs, transmute(entry));
 296          assert!(*entry.log_level == 3);
 297          assert!(m == 1);
 298      }
 299  }
 300  
 301  #[test]
 302  fn update_entry_match_beginning_longest_match() {
 303      let dirs = ~[LogDirective {name: Some(~"crate1::mod1"), level: 2 },
 304                   LogDirective {name: Some(~"crate2"), level: 3},
 305                   LogDirective {name: Some(~"crate2::mod"), level: 4}];
 306      let level = &mut 0;
 307      unsafe {
 308          let entry = &ModEntry {name: "crate2::mod1", log_level: level};
 309          let m = update_entry(dirs, transmute(entry));
 310          assert!(*entry.log_level == 4);
 311          assert!(m == 1);
 312      }
 313  }
 314  
 315  #[test]
 316  fn update_entry_match_default() {
 317      let dirs = ~[LogDirective {name: Some(~"crate1::mod1"), level: 2 },
 318                   LogDirective {name: None, level: 3}
 319                  ];
 320      let level = &mut 0;
 321      unsafe {
 322          let entry= &ModEntry {name: "crate1::mod1", log_level: level};
 323          let m = update_entry(dirs, transmute(entry));
 324          assert!(*entry.log_level == 2);
 325          assert!(m == 1);
 326          let entry= &ModEntry {name: "crate2::mod2", log_level: level};
 327          let m = update_entry(dirs, transmute(entry));
 328          assert!(*entry.log_level == 3);
 329          assert!(m == 1);
 330      }
 331  }

libstd/rt/logging.rs:60:68-60:68 -fn- definition:
/// Also supports string log levels of error, warn, info, and debug
fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
references:-
148:         dirs = parse_logging_spec(settings);


libstd/rt/logging.rs:30:82-30:82 -fn- definition:
/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
references:-
71:                 let possible_log_level = parse_log_level(parts[0]);
83:                 let possible_log_level = parse_log_level(parts[1]);


libstd/rt/logging.rs:20:1-20:1 -struct- definition:

struct LogDirective {
references:-
61: fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
101:         let dir = LogDirective {name: name, level: log_level};
109: fn update_entry(dirs: &[LogDirective], entry: &ModEntry) -> u32 {


libstd/rt/logging.rs:137:16-137:16 -fn- definition:
/// in settings
fn update_log_settings(crate_map: &CrateMap, settings: ~str) {
references:-
190:                     update_log_settings(crate_map, spec);
193:                     update_log_settings(crate_map, ~"");


libstd/rt/logging.rs:108:22-108:22 -fn- definition:
/// of log directives
fn update_entry(dirs: &[LogDirective], entry: &ModEntry) -> u32 {
references:-
153:         let m = update_entry(dirs, entry);


libstd/rt/logging.rs:164:1-164:1 -trait- definition:

pub trait Logger {
references:-
171: impl Logger for StdErrLogger {


libstd/rt/logging.rs:181:62-181:62 -fn- definition:
/// per-module global logging flags based on the logging spec
pub fn init() {
references:-
libstd/rt/mod.rs:
236:         logging::init();


libstd/rt/logging.rs:168:1-168:1 -struct- definition:

pub struct StdErrLogger;
references:-
171: impl Logger for StdErrLogger {
libstd/rt/task.rs:
48:     logger: StdErrLogger,