]> git.lizzy.rs Git - rust.git/blob - src/liblog/directive.rs
auto merge of #15999 : Kimundi/rust/fix_folder, r=nikomatsakis
[rust.git] / src / liblog / directive.rs
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::AsciiExt;
12 use std::cmp;
13
14 #[deriving(Show, Clone)]
15 pub struct LogDirective {
16     pub name: Option<String>,
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_string()),
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_string()));
84         assert_eq!(dirs[0].level, 1);
85
86         assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
87         assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);
88
89         assert_eq!(dirs[2].name, Some("crate2".to_string()));
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_string()));
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_string()));
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_string()));
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_string()));
132         assert_eq!(dirs[1].level, 4);
133     }
134 }