Skip to content

Commit

Permalink
Convert rust_log.cpp to Rust, closes rust-lang#8703
Browse files Browse the repository at this point in the history
  • Loading branch information
fhahn committed Sep 4, 2013
1 parent ed422b8 commit e38739b
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 190 deletions.
1 change: 0 additions & 1 deletion mk/rt.mk
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ RUNTIME_CXXS_$(1)_$(2) := \
rt/rust_upcall.cpp \
rt/rust_uv.cpp \
rt/rust_crate_map.cpp \
rt/rust_log.cpp \
rt/isaac/randport.cpp \
rt/miniz.cpp \
rt/memory_region.cpp \
Expand Down
263 changes: 248 additions & 15 deletions src/libstd/rt/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,159 @@
// <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 cast::transmute;
use either::*;
use libc;
use libc::{c_void, uintptr_t, c_char, exit, STDERR_FILENO};
use option::{Some, None};
use rt::util::dumb_println;
use str::StrSlice;
use str::raw::from_c_str;
use u32;
use unstable::raw::Closure;
use vec::ImmutableVector;


struct LogDirective {
name: ~str,
level: u32
}

// This is the Rust representation of the mod_entry struct in src/rt/rust_crate_map.h
struct ModEntry{
name: *c_char,
log_level: *mut u32
}

static MAX_LOG_DIRECTIVES: u32 = 255;
static MAX_LOG_LEVEL: u32 = 255;
static DEFAULT_LOG_LEVEL: u32 = 1;

fn iter_crate_map(map: *u8, f: &fn(*mut ModEntry)) {
unsafe {
let closure : Closure = transmute(f);
let code = transmute(closure.code);
let env = transmute(closure.env);
rust_iter_crate_map(transmute(map), iter_cb, code, env);
}

extern fn iter_cb(code: *c_void, env: *c_void, entry: *ModEntry){
unsafe {
let closure: Closure = Closure {
code: transmute(code),
env: transmute(env),
};
let closure: &fn(*ModEntry) = transmute(closure);
return closure(entry);
}
}
extern {
#[cfg(not(stage0))]
#[rust_stack]
fn rust_iter_crate_map(map: *c_void,
f: extern "C" fn(*c_void, *c_void, entry: *ModEntry),
code: *c_void,
data: *c_void);

#[cfg(stage0)]
#[rust_stack]
fn rust_iter_crate_map(map: *c_void,
f: *u8,
code: *c_void,
data: *c_void);
}
}

/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
/// and return a vector with log directives.
/// Valid log levels are 0-255, with the most likely ones being 0-3 (defined in std::).
fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
let mut dirs = ~[];
for s in spec.split_iter(',') {
let parts: ~[&str] = s.split_iter('=').collect();
let mut loglevel;
match parts.len() {
1 => loglevel = MAX_LOG_LEVEL,
2 => {
let num = u32::from_str(parts[1]);
match (num) {
Some(num) => {
if num < MAX_LOG_LEVEL {
loglevel = num;
} else {
loglevel = MAX_LOG_LEVEL;
}
}
_ => {
dumb_println(fmt!("warning: invalid logging spec \
'%s', ignoring it", s));
loop;
}
}
if loglevel > MAX_LOG_LEVEL { loglevel = MAX_LOG_LEVEL}
},
_ => {
dumb_println(fmt!("warning: invalid logging spec '%s',\
ignoring it", s));
loop;
}
}
let dir = LogDirective {name: parts[0].to_owned(), level: loglevel};
dirs.push(dir);
}
return dirs;
}

/// Set the log level of an entry in the crate map depending on the vector
/// of log directives
fn update_entry(dirs: &[LogDirective], entry: *mut ModEntry) -> u32 {
let mut new_lvl: u32 = DEFAULT_LOG_LEVEL;
let mut longest_match = 0;
unsafe {
for dir in dirs.iter() {
let name = from_c_str((*entry).name);
if name.starts_with(dir.name) && dir.name.len() > longest_match {
longest_match = dir.name.len();
new_lvl = dir.level;
}
}
*(*entry).log_level = new_lvl;
}
if longest_match > 0 { return 1; } else { return 0; }
}

#[fixed_stack_segment] #[inline(never)]
/// Set log level for every entry in crate_map according to the sepecification
/// in settings
fn update_log_settings(crate_map: *u8, settings: ~str) {
let mut dirs = ~[];
if settings.len() > 0 {
if settings == ~"::help" || settings == ~"?" {
dumb_println("\nCrate log map:\n");
do iter_crate_map(crate_map) |entry: *mut ModEntry| {
unsafe {
dumb_println(" "+from_c_str((*entry).name));
}
}
unsafe {
exit(1);
}
}
dirs = parse_logging_spec(settings);
}

let mut n_matches: u32 = 0;
do iter_crate_map(crate_map) |entry: *mut ModEntry| {
let m = update_entry(dirs, entry);
n_matches += m;
}

if n_matches < (dirs.len() as u32) {
dumb_println(fmt!("warning: got %u RUST_LOG specs but only matched %u of them.\n\
You may have mistyped a RUST_LOG spec.\n\
Use RUST_LOG=::help to see the list of crates and modules.\n",
dirs.len() as uint, n_matches as uint));
}
}

pub trait Logger {
fn log(&mut self, msg: Either<~str, &'static str>);
Expand Down Expand Up @@ -47,34 +196,26 @@ impl Logger for StdErrLogger {
};

fn print(s: &str) {
let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
let dbg = STDERR_FILENO as ::io::fd_t;
dbg.write_str(s);
dbg.write_str("\n");
dbg.flush();
}
}
}

/// Configure logging by traversing the crate map and setting the
/// per-module global logging flags based on the logging spec
#[fixed_stack_segment] #[inline(never)]
pub fn init(crate_map: *u8) {
use c_str::ToCStr;
use os;
use ptr;
use option::{Some, None};

let log_spec = os::getenv("RUST_LOG");
match log_spec {
Some(spec) => {
do spec.with_c_str |buf| {
unsafe { rust_update_log_settings(crate_map, buf) }
}
update_log_settings(crate_map, spec);
}
None => {
unsafe {
rust_update_log_settings(crate_map, ptr::null());
}
update_log_settings(crate_map, ~"");
}
}
}
Expand All @@ -89,9 +230,101 @@ pub fn console_off() { unsafe { rust_log_console_off() } }
fn should_log_console() -> bool { unsafe { rust_should_log_console() != 0 } }

extern {
fn rust_update_log_settings(crate_map: *u8, settings: *libc::c_char);
fn rust_log_console_on();
fn rust_log_console_off();
fn rust_should_log_console() -> libc::uintptr_t;
fn rust_should_log_console() -> uintptr_t;
}

// Tests for parse_logging_spec()
#[test]
fn parse_logging_spec_valid() {
let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=1,crate1::mod2,crate2=4");
assert_eq!(dirs.len(), 3);
assert!(dirs[0].name == ~"crate1::mod1");
assert_eq!(dirs[0].level, 1);
assert!(dirs[1].name == ~"crate1::mod2");
assert_eq!(dirs[1].level, MAX_LOG_LEVEL);
assert!(dirs[2].name == ~"crate2");
assert_eq!(dirs[2].level, 4);
}
#[test]
fn parse_logging_spec_invalid_crate() {
// test parse_logging_spec with multiple = in specification
let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=1=2,crate2=4");
assert_eq!(dirs.len(), 1);
assert!(dirs[0].name == ~"crate2");
assert_eq!(dirs[0].level, 4);
}
#[test]
fn parse_logging_spec_invalid_log_level() {
// test parse_logging_spec with 'noNumber' as log level
let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=noNumber,crate2=4");
assert_eq!(dirs.len(), 1);
assert!(dirs[0].name == ~"crate2");
assert_eq!(dirs[0].level, 4);
}
// Tests for update_entry
#[test]
fn update_entry_match_full_path() {
use c_str::ToCStr;
let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
LogDirective {name: ~"crate2", level: 3}];
unsafe {
do "crate1::mod1".to_c_str().with_ref |ptr| {
let entry= &ModEntry {name: ptr, log_level: &mut 0};
let m = update_entry(dirs, transmute(entry));
assert!(*entry.log_level == 2);
assert!(m == 1);
}
}
}
#[test]
fn update_entry_no_match() {
use c_str::ToCStr;
let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
LogDirective {name: ~"crate2", level: 3}];
unsafe {
do "crate3::mod1".to_c_str().with_ref |ptr| {
let entry= &ModEntry {name: ptr, log_level: &mut 0};
let m = update_entry(dirs, transmute(entry));
assert!(*entry.log_level == DEFAULT_LOG_LEVEL);
assert!(m == 0);
}
}
}
#[test]
fn update_entry_match_beginning() {
use c_str::ToCStr;
let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
LogDirective {name: ~"crate2", level: 3}];
unsafe {
do "crate2::mod1".to_c_str().with_ref |ptr| {
let entry= &ModEntry {name: ptr, log_level: &mut 0};
let m = update_entry(dirs, transmute(entry));
assert!(*entry.log_level == 3);
assert!(m == 1);
}
}
}
#[test]
fn update_entry_match_beginning_longest_match() {
use c_str::ToCStr;
let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
LogDirective {name: ~"crate2", level: 3}, LogDirective {name: ~"crate2::mod", level: 4}];
unsafe {
do "crate2::mod1".to_c_str().with_ref |ptr| {
let entry = &ModEntry {name: ptr, log_level: &mut 0};
let m = update_entry(dirs, transmute(entry));
assert!(*entry.log_level == 4);
assert!(m == 1);
}
}
}
38 changes: 27 additions & 11 deletions src/rt/rust_crate_map.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand All @@ -12,36 +12,52 @@
#include <set>

void iter_module_map(const mod_entry* map,
void (*fn)(const mod_entry* entry, void *cookie),
void *cookie) {
void (*fn)(void* fptr, void* env, const mod_entry *entry),
void* fptr,
void* env
) {
for (const mod_entry* cur = map; cur->name; cur++) {
fn(cur, cookie);
fn(fptr, env, cur);
}
}

void iter_crate_map(const cratemap* map,
void (*fn)(const mod_entry* map, void *cookie),
void *cookie,
void (*fn)(void* fptr, void* env, const mod_entry *entry),
void *fptr,
void *env,
std::set<const cratemap*>& visited) {
if (visited.find(map) == visited.end()) {
// Mark this crate visited
visited.insert(map);
// First iterate this crate
iter_module_map(map->entries(), fn, cookie);
iter_module_map(map->entries(), fn, fptr, env);
// Then recurse on linked crates
for (cratemap::iterator i = map->begin(),
e = map->end(); i != e; ++i) {
iter_crate_map(*i, fn, cookie, visited);
iter_crate_map(*i, fn, fptr, env, visited);
}
}
}

void iter_crate_map(const cratemap* map,
void (*fn)(const mod_entry* map, void *cookie),
void *cookie) {
void (*fn)(void* fptr, void* env, const mod_entry *entry),
void *fptr,
void *env
) {
std::set<const cratemap*> visited;
iter_crate_map(map, fn, cookie, visited);
iter_crate_map(map, fn, fptr, env, visited);
}

extern "C" CDECL void
rust_iter_crate_map(const cratemap* map,
void (*fn)(void* fptr, void* env, const mod_entry *entry),
void *fptr,
void *env
) {
return iter_crate_map(map, fn, fptr, env);
}


//
// Local Variables:
// mode: C++
Expand Down
Loading

0 comments on commit e38739b

Please sign in to comment.