Skip to content

Commit cc6ec8d

Browse files
committed
log: Introduce liblog, the old std::logging
This commit moves all logging out of the standard library into an external crate. This crate is the new crate which is responsible for all logging macros and logging implementation. A few reasons for this change are: * The crate map has always been a bit of a code smell among rust programs. It has difficulty being loaded on almost all platforms, and it's used almost exclusively for logging and only logging. Removing the crate map is one of the end goals of this movement. * The compiler has a fair bit of special support for logging. It has the __log_level() expression as well as generating a global word per module specifying the log level. This is unfairly favoring the built-in logging system, and is much better done purely in libraries instead of the compiler itself. * Initialization of logging is much easier to do if there is no reliance on a magical crate map being available to set module log levels. * If the logging library can be written outside of the standard library, there's no reason that it shouldn't be. It's likely that we're not going to build the highest quality logging library of all time, so third-party libraries should be able to provide just as high-quality logging systems as the default one provided in the rust distribution. With a migration such as this, the change does not come for free. There are some subtle changes in the behavior of liblog vs the previous logging macros: * The core change of this migration is that there is no longer a physical log-level per module. This concept is still emulated (it is quite useful), but there is now only a global log level, not a local one. This global log level is a reflection of the maximum of all log levels specified. The previously generated logging code looked like: if specified_level <= __module_log_level() { println!(...) } The newly generated code looks like: if specified_level <= ::log::LOG_LEVEL { if ::log::module_enabled(module_path!()) { println!(...) } } Notably, the first layer of checking is still intended to be "super fast" in that it's just a load of a global word and a compare. The second layer of checking is executed to determine if the current module does indeed have logging turned on. This means that if any module has a debug log level turned on, all modules with debug log levels get a little bit slower (they all do more expensive dynamic checks to determine if they're turned on or not). Semantically, this migration brings no change in this respect, but runtime-wise, this will have a perf impact on some code. * A `RUST_LOG=::help` directive will no longer print out a list of all modules that can be logged. This is because the crate map will no longer specify the log levels of all modules, so the list of modules is not known. Additionally, warnings can no longer be provided if a malformed logging directive was supplied. The new "hello world" for logging looks like: #[phase(syntax, link)] extern crate log; fn main() { debug!("Hello, world!"); }
1 parent e49c30a commit cc6ec8d

File tree

368 files changed

+1577
-1571
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

368 files changed

+1577
-1571
lines changed

mk/crates.mk

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
TARGET_CRATES := std green rustuv native flate arena glob term semver \
5353
uuid serialize sync getopts collections num test time rand \
54-
workcache url
54+
workcache url log
5555
HOST_CRATES := syntax rustc rustdoc fourcc hexfloat
5656
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
5757
TOOLS := compiletest rustdoc rustc
@@ -60,15 +60,15 @@ DEPS_std := native:rustrt native:compiler-rt native:backtrace
6060
DEPS_green := std rand native:context_switch
6161
DEPS_rustuv := std native:uv native:uv_support
6262
DEPS_native := std
63-
DEPS_syntax := std term serialize collections
63+
DEPS_syntax := std term serialize collections log
6464
DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \
65-
collections time
65+
collections time log
6666
DEPS_rustdoc := rustc native:sundown serialize sync getopts collections \
6767
test time
6868
DEPS_flate := std native:miniz
6969
DEPS_arena := std collections
7070
DEPS_glob := std
71-
DEPS_serialize := std collections
71+
DEPS_serialize := std collections log
7272
DEPS_term := std collections
7373
DEPS_semver := std
7474
DEPS_uuid := std serialize rand
@@ -83,6 +83,7 @@ DEPS_time := std serialize
8383
DEPS_rand := std
8484
DEPS_url := std collections
8585
DEPS_workcache := std serialize collections std
86+
DEPS_log := std sync
8687

8788
TOOL_DEPS_compiletest := test green rustuv getopts
8889
TOOL_DEPS_rustdoc := rustdoc native

src/compiletest/compiletest.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
// except according to those terms.
1010

1111
#[crate_type = "bin"];
12+
#[feature(phase)];
1213

1314
#[allow(non_camel_case_types)];
1415
#[deny(warnings)];
1516
#[allow(deprecated_owned_vector)];
1617

1718
extern crate test;
1819
extern crate getopts;
20+
#[phase(link, syntax)]
21+
extern crate log;
1922

2023
use std::os;
2124
use std::io;

src/doc/rust.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1055,7 +1055,7 @@ output slot type would normally be. For example:
10551055

10561056
~~~~
10571057
fn my_err(s: &str) -> ! {
1058-
info!("{}", s);
1058+
println!("{}", s);
10591059
fail!();
10601060
}
10611061
~~~~
@@ -3885,6 +3885,9 @@ Rust provides several macros to log information. Here's a simple Rust program
38853885
that demonstrates all four of them:
38863886

38873887
~~~~
3888+
#[feature(phase)];
3889+
#[phase(syntax, link)] extern crate log;
3890+
38883891
fn main() {
38893892
error!("This is an error log")
38903893
warn!("This is a warn log")

src/doc/tutorial.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ unit, `()`, as the empty tuple if you like).
796796
~~~~
797797
let mytup: (int, int, f64) = (10, 20, 30.0);
798798
match mytup {
799-
(a, b, c) => info!("{}", a + b + (c as int))
799+
(a, b, c) => println!("{}", a + b + (c as int))
800800
}
801801
~~~~
802802

@@ -813,7 +813,7 @@ For example:
813813
struct MyTup(int, int, f64);
814814
let mytup: MyTup = MyTup(10, 20, 30.0);
815815
match mytup {
816-
MyTup(a, b, c) => info!("{}", a + b + (c as int))
816+
MyTup(a, b, c) => println!("{}", a + b + (c as int))
817817
}
818818
~~~~
819819

@@ -1794,7 +1794,7 @@ use std::task::spawn;
17941794
17951795
// proc is the closure which will be spawned.
17961796
spawn(proc() {
1797-
debug!("I'm a new task")
1797+
println!("I'm a new task")
17981798
});
17991799
~~~~
18001800

src/libcollections/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
2121
html_root_url = "http://static.rust-lang.org/doc/master")];
2222

23-
#[feature(macro_rules, managed_boxes, default_type_params)];
23+
#[feature(macro_rules, managed_boxes, default_type_params, phase)];
2424

2525
// NOTE remove the following two attributes after the next snapshot.
2626
#[allow(unrecognized_lint)];
@@ -30,6 +30,7 @@
3030
extern crate rand;
3131

3232
#[cfg(test)] extern crate test;
33+
#[cfg(test)] #[phase(syntax, link)] extern crate log;
3334

3435
pub use bitv::Bitv;
3536
pub use btree::BTree;

src/libflate/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ Simple compression
1818
#[crate_type = "rlib"];
1919
#[crate_type = "dylib"];
2020
#[license = "MIT/ASL2"];
21-
#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
2221
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
2322
html_root_url = "http://static.rust-lang.org/doc/master")];
23+
#[feature(phase)];
24+
25+
#[cfg(test)] #[phase(syntax, link)] extern crate log;
2426

2527
use std::libc::{c_void, size_t, c_int};
2628
use std::libc;

src/libgetopts/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@
8686
#[allow(missing_doc)];
8787
#[allow(deprecated_owned_vector)];
8888

89-
#[feature(globs)];
89+
#[feature(globs, phase)];
90+
91+
#[cfg(test)] #[phase(syntax, link)] extern crate log;
9092

9193
use std::cmp::Eq;
9294
use std::result::{Err, Ok};

src/libgreen/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,11 @@
172172
html_root_url = "http://static.rust-lang.org/doc/master")];
173173

174174
// NB this does *not* include globs, please keep it that way.
175-
#[feature(macro_rules)];
175+
#[feature(macro_rules, phase)];
176176
#[allow(visible_private_types)];
177177
#[allow(deprecated_owned_vector)];
178178

179+
#[cfg(test)] #[phase(syntax, link)] extern crate log;
179180
extern crate rand;
180181

181182
use std::mem::replace;

src/libgreen/task.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,13 @@ impl GreenTask {
178178
f: proc()) -> ~GreenTask {
179179
let TaskOpts {
180180
notify_chan, name, stack_size,
181-
stderr, stdout, logger,
181+
stderr, stdout,
182182
} = opts;
183183

184184
let mut green = GreenTask::new(pool, stack_size, f);
185185
{
186186
let task = green.task.get_mut_ref();
187187
task.name = name;
188-
task.logger = logger;
189188
task.stderr = stderr;
190189
task.stdout = stdout;
191190
match notify_chan {

src/liblog/directive.rs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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+
use std::vec_ng::Vec;
13+
14+
#[deriving(Show, Clone)]
15+
pub struct LogDirective {
16+
name: Option<~str>,
17+
level: u32,
18+
}
19+
20+
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 == 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"));
84+
assert_eq!(dirs[0].level, 1);
85+
86+
assert_eq!(dirs[1].name, Some(~"crate1::mod2"));
87+
assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);
88+
89+
assert_eq!(dirs[2].name, Some(~"crate2"));
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"));
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"));
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"));
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"));
132+
assert_eq!(dirs[1].level, 4);
133+
}
134+
}

0 commit comments

Comments
 (0)