Refactor the logging system for fewer allocations

This lifts various restrictions on the runtime, for example the character limit
when logging a message. Right now the old debug!-style macros still involve
allocating (because they use fmt! syntax), but the new debug2! macros don't
involve allocating at all (unless the formatter for a type requires allocation.
This commit is contained in:
Alex Crichton 2013-08-28 01:33:48 -07:00
parent af25f58ac3
commit eb2b25dd6d
7 changed files with 83 additions and 138 deletions

View File

@ -10,11 +10,11 @@
//! Logging
use fmt;
use option::*;
use os;
use rt;
use rt::logging::{Logger, StdErrLogger};
use send_str::SendStrOwned;
/// Turns on logging to stdout globally
pub fn console_on() {
@ -37,7 +37,17 @@ pub fn console_off() {
rt::logging::console_off();
}
fn newsched_log_str(msg: ~str) {
#[cfg(stage0)]
#[doc(hidden)]
pub fn log(_level: u32, s: ~str) {
// this is a terrible approximation, but it gets the job done (for stage0 at
// least)
::io::println(s);
}
#[allow(missing_doc)]
#[cfg(not(stage0))]
pub fn log(_level: u32, args: &fmt::Arguments) {
use rt::task::Task;
use rt::local::Local;
@ -46,20 +56,13 @@ fn newsched_log_str(msg: ~str) {
match optional_task {
Some(local) => {
// Use the available logger
(*local).logger.log(SendStrOwned(msg));
(*local).logger.log(args);
}
None => {
// There is no logger anywhere, just write to stderr
let mut logger = StdErrLogger;
logger.log(SendStrOwned(msg));
logger.log(args);
}
}
}
}
// XXX: This will change soon to not require an allocation. This is an unstable
// api which should not be used outside of the macros in ext/expand.
#[doc(hidden)]
pub fn log(_level: u32, msg: ~str) {
newsched_log_str(msg);
}

View File

@ -7,9 +7,12 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use fmt;
use from_str::from_str;
use libc::{uintptr_t, exit, STDERR_FILENO};
use libc::{uintptr_t, exit};
use option::{Some, None, Option};
use rt;
use rt::util::dumb_println;
use rt::crate_map::{ModEntry, iter_crate_map};
use rt::crate_map::get_crate_map;
@ -18,7 +21,6 @@ use str::raw::from_c_str;
use u32;
use vec::ImmutableVector;
use cast::transmute;
use send_str::{SendStr, SendStrOwned, SendStrStatic};
struct LogDirective {
name: Option<~str>,
@ -171,44 +173,33 @@ fn update_log_settings(crate_map: *u8, settings: ~str) {
}
pub trait Logger {
fn log(&mut self, msg: SendStr);
fn log(&mut self, args: &fmt::Arguments);
}
pub struct StdErrLogger;
impl Logger for StdErrLogger {
fn log(&mut self, msg: SendStr) {
use io::{Writer, WriterUtil};
if !should_log_console() {
return;
}
let s: &str = match msg {
SendStrOwned(ref s) => {
let slc: &str = *s;
slc
},
SendStrStatic(s) => s,
};
// Truncate the string
let buf_bytes = 2048;
if s.len() > buf_bytes {
let s = s.slice(0, buf_bytes) + "[...]";
print(s);
} else {
print(s)
};
fn print(s: &str) {
let dbg = STDERR_FILENO as ::io::fd_t;
dbg.write_str(s);
dbg.write_str("\n");
dbg.flush();
fn log(&mut self, args: &fmt::Arguments) {
if should_log_console() {
fmt::write(self as &mut rt::io::Writer, args);
}
}
}
impl rt::io::Writer for StdErrLogger {
fn write(&mut self, buf: &[u8]) {
// Nothing like swapping between I/O implementations! In theory this
// could use the libuv bindings for writing to file descriptors, but
// that may not necessarily be desirable because logging should work
// outside of the uv loop. (modify with caution)
use io::Writer;
let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
dbg.write(buf);
}
fn flush(&mut self) {}
}
/// Configure logging by traversing the crate map and setting the
/// per-module global logging flags based on the logging spec
pub fn init() {

View File

@ -224,4 +224,5 @@ mod std {
pub use os;
pub use fmt;
pub use to_bytes;
pub use logging;
}

View File

@ -125,14 +125,41 @@ impl FailWithCause for &'static str {
}
}
// FIXME #4427: Temporary until rt::rt_fail_ goes away
// This stage0 version is incredibly wrong.
#[cfg(stage0)]
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
use option::{Some, None};
use rt::in_green_task_context;
use rt::task::Task;
use rt::local::Local;
use rt::logging::Logger;
use send_str::SendStrOwned;
use str::Str;
unsafe {
let msg = str::raw::from_c_str(msg);
let file = str::raw::from_c_str(file);
if in_green_task_context() {
rterrln!("task failed at '%s', %s:%i", msg, file, line as int);
} else {
rterrln!("failed in non-task context at '%s', %s:%i",
msg, file, line as int);
}
let task: *mut Task = Local::unsafe_borrow();
if (*task).unwinder.unwinding {
rtabort!("unwinding again");
}
(*task).unwinder.begin_unwind();
}
}
// FIXME #4427: Temporary until rt::rt_fail_ goes away
#[cfg(not(stage0))]
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
use rt::in_green_task_context;
use rt::task::Task;
use rt::local::Local;
use rt::logging::Logger;
use str::Str;
unsafe {
@ -140,22 +167,14 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
let msg = str::raw::from_c_str(msg);
let file = str::raw::from_c_str(file);
// XXX: Logging doesn't work correctly in non-task context because it
// invokes the local heap
if in_green_task_context() {
// XXX: Logging doesn't work here - the check to call the log
// function never passes - so calling the log function directly.
// Be careful not to allocate in this block, if we're failing we may
// have been failing due to a lack of memory in the first place...
do Local::borrow |task: &mut Task| {
let msg = match task.name {
Some(ref name) =>
fmt!("task '%s' failed at '%s', %s:%i",
name.as_slice(), msg, file, line as int),
None =>
fmt!("task <unnamed> failed at '%s', %s:%i",
msg, file, line as int)
};
task.logger.log(SendStrOwned(msg));
let n = task.name.map(|n| n.as_slice()).unwrap_or("<unnamed>");
format_args!(|args| { task.logger.log(args) },
"task '{}' failed at '{}', {}:{}",
n, msg.as_slice(), file.as_slice(), line);
}
} else {
rterrln!("failed in non-task context at '%s', %s:%i",

View File

@ -813,13 +813,17 @@ pub fn std_macros() -> @str {
($lvl:expr, $arg:expr) => ({
let lvl = $lvl;
if lvl <= __log_level() {
::std::logging::log(lvl, fmt!(\"%?\", $arg))
format_args!(|args| {
::std::logging::log(lvl, args)
}, \"{}\", fmt!(\"%?\", $arg))
}
});
($lvl:expr, $($arg:expr),+) => ({
let lvl = $lvl;
if lvl <= __log_level() {
::std::logging::log(lvl, fmt!($($arg),+))
format_args!(|args| {
::std::logging::log(lvl, args)
}, \"{}\", fmt!($($arg),+))
}
})
)
@ -834,7 +838,9 @@ pub fn std_macros() -> @str {
($lvl:expr, $($arg:tt)+) => ({
let lvl = $lvl;
if lvl <= __log_level() {
::std::logging::log(lvl, format!($($arg)+))
format_args!(|args| {
::std::logging::log(lvl, args)
}, $($arg)+)
}
})
)

View File

@ -20,6 +20,5 @@ impl Drop for C {
fn main() {
let c = C{ x: 2};
let d = c.clone(); //~ ERROR does not implement any method in scope
error!("%?", d.x);
let _d = c.clone(); //~ ERROR does not implement any method in scope
}

View File

@ -1,74 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that logs add `[...]` to truncated lines
// error-pattern:[...]
fn main() {
fail!("\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
");
}