--- AnyEvent/lib/AnyEvent/Log.pm 2011/09/05 07:21:54 1.43 +++ AnyEvent/lib/AnyEvent/Log.pm 2012/03/22 19:27:30 1.52 @@ -8,15 +8,30 @@ use AnyEvent; - AE::log debug => "hit my knee"; - AE::log warn => "it's a bit too hot"; - AE::log error => "the flag was false!"; - AE::log fatal => "the bit toggled! run!"; # never returns + AE::log fatal => "no config found, cannot continue"; # never returns + AE::log alert => "the battery died"; + AE::log crit => "the battery temperature is too hot"; + AE::log error => "division by zero attempted"; + AE::log warn => "couldn't delete the file"; + AE::log note => "wanted to create config, but config already exists"; + AE::log info => "file soandso successfully deleted"; + AE::log debug => "the function returned 3"; + AE::log trace => "going to call function abc"; - # available log levels in order: - # fatal alert critical error warn note info debug trace +Log level overview: -"Complex" uses (for speed sensitive code): + LVL NAME SYSLOG PERL NOTE + 1 fatal emerg exit system unusable, aborts program! + 2 alert failure in primary system + 3 critical crit failure in backup system + 4 error err die non-urgent program errors, a bug + 5 warn warning possible problem, not necessarily error + 6 note notice unusual conditions + 7 info normal messages, no action required + 8 debug debugging messages for development + 9 trace copious tracing output + +"Complex" uses (for speed sensitive code, e.g. trace/debug messages): use AnyEvent::Log; @@ -48,10 +63,11 @@ module more or less exposes the mechanism, with some extra spiff to allow using it from other modules as well. -Remember that the default verbosity level is C<0> (C), so nothing -will be logged, unless you set C to a higher number -before starting your program, or change the logging level at runtime with -something like: +Remember that the default verbosity level is C<4> (C), so only +errors and more important messages will be logged, unless you set +C to a higher number before starting your program +(C is recommended during development), or change the logging +level at runtime with something like: use AnyEvent::Log; $AnyEvent::Log::FILTER->level ("info"); @@ -93,24 +109,28 @@ messages at C priority. The NOTE column tries to provide some rationale on how to chose a logging level. -As a rough guideline, levels 1..3 are primarily meant for users of -the program (admins, staff), and are the only logged to STDERR by +As a rough guideline, levels 1..3 are primarily meant for users of the +program (admins, staff), and are the only ones logged to STDERR by default. Levels 4..6 are meant for users and developers alike, while levels 7..9 are usually meant for developers. -You can normally only log a single message at highest priority level -(C<1>, C), because logging a fatal message will also quit the -program - so use it sparingly :) +You can normally only log a message once at highest priority level (C<1>, +C), because logging a fatal message will also quit the program - so +use it sparingly :) + +For example, a program that finds an unknown switch on the commandline +might well use a fatal logging level to tell users about it - the "system" +in this case would be the program, or module. Some methods also offer some extra levels, such as C<0>, C, C -or C - these are only valid in the methods they are documented for. +or C - these are only valid for the methods that documented them. =head1 LOGGING FUNCTIONS -These functions allow you to log messages. They always use the caller's -package as a "logging context". Also, the main logging function C is -callable as C or C when the C module is -loaded. +The following functions allow you to log messages. They always use the +caller's package as a "logging context". Also, the main logging function, +C, is aliased to C and C when the C +module is loaded. =over 4 @@ -121,6 +141,10 @@ use Carp (); use POSIX (); +# layout of a context +# 0 1 2 3 4, 5 +# [$title, $level, %$slaves, &$logcb, &$fmtcb, $cap] + use AnyEvent (); BEGIN { AnyEvent::common_sense } #use AnyEvent::Util (); need to load this in a delayed fashion, as it uses AE::log @@ -175,6 +199,9 @@ actually gets logged, which is useful if it is costly to create the message in the first place. +This function takes care of saving and restoring C<$!> and C<$@>, so you +don't have to. + Whether the given message will be logged depends on the maximum log level and the caller's package. The return value can be used to ensure that messages or not "lost" - for example, when L detects a @@ -264,15 +291,28 @@ my $mask = 1 << $level; - my ($success, %seen, @ctx, $now, $fmt); + my ($success, %seen, @ctx, $now, @fmt); do { - # skip if masked - if ($ctx->[1] & $mask && !$seen{$ctx+0}++) { + # if !ref, then it's a level number + if (!ref $ctx) { + $level = $ctx; + } elsif ($ctx->[1] & $mask and !$seen{$ctx+0}++) { + # logging/recursing into this context + + # level cap + if ($ctx->[5] > $level) { + push @ctx, $level; # restore level when going up in tree + $level = $ctx->[5]; + } + + # log if log cb if ($ctx->[3]) { # logging target found + local ($!, $@); + # now get raw message, unless we have it already unless ($now) { $format = $format->() if ref $format; @@ -284,7 +324,7 @@ # format msg my $str = $ctx->[4] ? $ctx->[4]($now, $_[0], $level, $format) - : ($fmt ||= _format $now, $_[0], $level, $format); + : ($fmt[$level] ||= _format $now, $_[0], $level, $format); $success = 1; @@ -598,9 +638,6 @@ package AnyEvent::Log::Ctx; -# 0 1 2 3 4 -# [$title, $level, %$slaves, &$logcb, &$fmtcb] - =item $ctx = new AnyEvent::Log::Ctx methodname => param... This is a convenience constructor that makes it simpler to construct @@ -697,6 +734,28 @@ Disables logging for the given levels, leaving all others unchanged. +=item $ctx->cap ($level) + +Caps the maximum priority to the given level, for all messages logged +to, or passing through, this context. That is, while this doesn't affect +whether a message is logged or passed on, the maximum priority of messages +will be limited to the specified level - messages with a higher priority +will be set to the specified priority. + +Another way to view this is that C<< ->level >> filters out messages with +a too low priority, while C<< ->cap >> modifies messages with a too high +priority. + +This is useful when different log targets have different interpretations +of priority. For example, for a specific command line program, a wrong +command line switch might well result in a C log message, while the +same message, logged to syslog, is likely I fatal to the system or +syslog facility as a whole, but more likely a mere C. + +This can be modeled by having a stderr logger that logs messages "as-is" +and a syslog logger that logs messages with a level cap of, say, C, +or, for truly system-critical components, actually C. + =cut sub _lvl_lst { @@ -707,6 +766,10 @@ } @_ } +sub _lvl { + $_[0] =~ /^(?:0|off|none)$/ ? 0 : (_lvl_lst $_[0])[-1] +} + our $NOP_CB = sub { 0 }; sub levels { @@ -719,9 +782,7 @@ sub level { my $ctx = shift; - my $lvl = $_[0] =~ /^(?:0|off|none)$/ ? 0 : (_lvl_lst $_[0])[-1]; - - $ctx->[1] = ((1 << $lvl) - 1) << 1; + $ctx->[1] = ((1 << &_lvl) - 1) << 1; AnyEvent::Log::_reassess; } @@ -739,6 +800,11 @@ AnyEvent::Log::_reassess; } +sub cap { + my $ctx = shift; + $ctx->[5] = &_lvl; +} + =back =head3 SLAVE CONTEXTS @@ -835,12 +901,12 @@ default formatter). The callback is passed the (possibly fractional) timestamp, the original -logging context, the (numeric) logging level and the raw message string -and needs to return a formatted log message. In most cases this will be a -string, but it could just as well be an array reference that just stores -the values. +logging context (object, not title), the (numeric) logging level and +the raw message string and needs to return a formatted log message. In +most cases this will be a string, but it could just as well be an array +reference that just stores the values. -If, for some reason, you want to use C to find out more baout the +If, for some reason, you want to use C to find out more about the logger then you should walk up the call stack until you are no longer inside the C package. @@ -854,7 +920,7 @@ }); Example: return an array reference with just the log values, and use -C to store the emssage in a database. +C to store the message in a database. $ctx->fmt_cb (sub { \@_ }); $ctx->log_cb (sub { @@ -982,6 +1048,10 @@ Same as C, but uses the given context as log context. +Example: log a message in the context of another package. + + (AnyEvent::Log::ctx "Other::Package")->log (warn => "heely bo"); + =item $logger = $ctx->logger ($level[, \$enabled]) Same as C, but uses the given context as log @@ -1078,9 +1148,15 @@ Configures the context to not log anything by itself, which is the default. Same as C<< $ctx->log_cb (undef) >>. +=item CI + +Caps logging messages entering this context at the given level, i.e. +reduces the priority of messages with higher priority than this level. The +default is C<0> (or C), meaning the priority will not be touched. + =item C<0> or C -Sets the logging level of the context ot C<0>, i.e. all messages will be +Sets the logging level of the context to C<0>, i.e. all messages will be filtered out. =item C @@ -1132,7 +1208,7 @@ =item C<+> -A line C<+> detaches all contexts, i.e. clears the slave list from the +A lone C<+> detaches all contexts, i.e. clears the slave list from the context. Anonymous (C<%name>) contexts have no attached slaves by default, but package contexts have the parent context as slave by default. @@ -1173,7 +1249,7 @@ $_[0] eq "log" ? $LOG : $_[0] eq "filter" ? $FILTER : $_[0] eq "collect" ? $COLLECT - : $_[0] =~ /^%(.+)$/ ? ($anon{$1} ||= ctx undef) + : $_[0] =~ /^%(.+)$/ ? ($anon{$1} ||= do { my $ctx = ctx undef; $ctx->[0] = $_[0]; $ctx }) : $_[0] =~ /^(.*?)(?:::)?$/ ? ctx "$1" # egad :/ : die # never reached? }; @@ -1189,8 +1265,9 @@ if ($_ eq "stderr" ) { $ctx->log_to_warn; } elsif (/^file=(.+)/ ) { $ctx->log_to_file ("$1"); } elsif (/^path=(.+)/ ) { $ctx->log_to_path ("$1"); - } elsif (/syslog(?:=(.*))?/ ) { require Sys::Syslog; $ctx->log_to_syslog ($1); + } elsif (/^syslog(?:=(.*))?/ ) { require Sys::Syslog; $ctx->log_to_syslog ("$1"); } elsif ($_ eq "nolog" ) { $ctx->log_cb (undef); + } elsif (/^cap=(.+)/ ) { $ctx->cap ("$1"); } elsif (/^\+(.+)$/ ) { $ctx->attach ($pkg->("$1")); } elsif ($_ eq "+" ) { $ctx->slaves; } elsif ($_ eq "off" or $_ eq "0") { $ctx->level (0); @@ -1268,6 +1345,23 @@ In both cases, messages are still written to STDERR. +=item Additionally log all messages with C and higher priority to +C, but cap at C. + +This logs all messages to the default log target, but also logs messages +with priority C or higher (and not filtered otherwise) to syslog +facility C. Messages with priority higher than C will be +logged with level C. + + $AnyEvent::Log::LOG->attach ( + new AnyEvent::Log::Ctx + level => "warn", + cap => "error", + syslog => "user", + ); + + PERL_ANYEVENT_LOG=log=+%syslog:%syslog=warn,cap=error,syslog + =item Write trace messages (only) from L to the default logging target(s). Attach the C<$AnyEvent::Log::LOG> context to the C