(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 }