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