bunpen: logging: annotate log statements with the PID issuing the log
This commit is contained in:
65
pkgs/by-name/bunpen/log/annotated/annotatedlogger.ha
Normal file
65
pkgs/by-name/bunpen/log/annotated/annotatedlogger.ha
Normal file
@@ -0,0 +1,65 @@
|
||||
// vim: set shiftwidth=2 :
|
||||
//
|
||||
// the "annotated logger" logs each incoming entry, prepended with additional
|
||||
// information (such as the pid which triggered the log statement).
|
||||
//
|
||||
// TODO: pids logged here suffer from aliasing, when using PID namespaces;
|
||||
// i could de-alias these by (either):
|
||||
// 1. maintaining global state that is a sequence of pids, and appending to this
|
||||
// on each fork. e.g. `[pid=19332/2/4]`.
|
||||
// however siblings each placed in a new PID space will still have aliasing.
|
||||
// 2. maintaining global state that is a sequence of pids, and appending to this
|
||||
// on each fork, by piping the fork'd PID from parent into child.
|
||||
// by using the parent's view, siblings are no longer aliased.
|
||||
|
||||
use fmt;
|
||||
use log;
|
||||
use rt;
|
||||
|
||||
export type logger = struct {
|
||||
// vtable (println, printfln)
|
||||
base: log::logger,
|
||||
// where to forward logs
|
||||
forward: nullable *log::logger,
|
||||
};
|
||||
|
||||
let _global: logger = logger {
|
||||
base = log::logger {
|
||||
println = &log_println,
|
||||
printfln = &log_printfln,
|
||||
},
|
||||
forward = null, // can't evaluate &log::default at compile time, so set null
|
||||
};
|
||||
|
||||
// annotatedlogger with program lifetime, in case you don't want to manage that yourself
|
||||
export const global: *logger = &_global;
|
||||
|
||||
export fn set_forward(me: *logger, forward: *log::logger) void = {
|
||||
me.forward = forward;
|
||||
};
|
||||
|
||||
fn log_println(base: *log::logger, fields: fmt::formattable...) void = {
|
||||
// no way to nest `printf("[pid={}]: {}", getpid(), print(fields...))`
|
||||
// except by evaluating the inner printf:
|
||||
let entry = fmt::asprint(fields...);
|
||||
defer free(entry);
|
||||
log_println1(base, entry);
|
||||
};
|
||||
fn log_printfln(base: *log::logger, fmt: str, fields: fmt::field...) void = {
|
||||
// no way to nest `printf("[pid={}]: {}", getpid(), printf(fmt, fields...))`
|
||||
// except by evaluating the inner printf:
|
||||
let entry = fmt::asprintf(fmt, fields...);
|
||||
defer free(entry);
|
||||
log_println1(base, entry);
|
||||
};
|
||||
fn log_println1(base: *log::logger, entry: str) void = {
|
||||
let me = base: *logger;
|
||||
log::lprintfln(get_forward(me), "[pid={}] {}", rt::getpid(): int, entry);
|
||||
};
|
||||
|
||||
fn get_forward(me: *logger) *log::logger = {
|
||||
return match (me.forward) {
|
||||
case null => yield log::default;
|
||||
case let l: *log::logger => yield l;
|
||||
};
|
||||
};
|
@@ -48,6 +48,10 @@ export fn set_level(me: *logger, level: uint) void = {
|
||||
me.level = level;
|
||||
};
|
||||
|
||||
export fn set_forward(me: *logger, forward: *log::logger) void = {
|
||||
me.forward = forward;
|
||||
};
|
||||
|
||||
fn log_println(base: *log::logger, fields: fmt::formattable...) void = {
|
||||
let me = base: *logger;
|
||||
if (me.level > 0 && (len(fields) == 0 || get_depth(fields[0]) < me.level)) {
|
||||
|
@@ -3,6 +3,7 @@ use config;
|
||||
use errors;
|
||||
use errors::ext;
|
||||
use log;
|
||||
use log::annotated;
|
||||
use log::tree;
|
||||
use restrict;
|
||||
use restrict::ns;
|
||||
@@ -47,6 +48,7 @@ fn prepare_env(req: config::cli_request) config::exec_params = {
|
||||
|
||||
export fn main() void = {
|
||||
// install my logger, but defaulted to no logging.
|
||||
log::tree::set_forward(tree::global, log::annotated::global);
|
||||
log::tree::install(tree::global);
|
||||
|
||||
let opts = match (config::parse_args(os::args[1..])) {
|
||||
|
Reference in New Issue
Block a user