NAME¶
Log::Log4perl::Filter - Log4perl Custom Filter Base Class
SYNOPSIS¶
use Log::Log4perl;
Log::Log4perl->init(\ <<'EOT');
log4perl.logger = INFO, Screen
log4perl.filter.MyFilter = sub { /let this through/ }
log4perl.appender.Screen = Log::Log4perl::Appender::Screen
log4perl.appender.Screen.Filter = MyFilter
log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
EOT
# Define a logger
my $logger = Log::Log4perl->get_logger("Some");
# Let this through
$logger->info("Here's the info, let this through!");
# Suppress this
$logger->info("Here's the info, suppress this!");
#################################################################
# StringMatch Filter:
#################################################################
log4perl.filter.M1 = Log::Log4perl::Filter::StringMatch
log4perl.filter.M1.StringToMatch = let this through
log4perl.filter.M1.AcceptOnMatch = true
#################################################################
# LevelMatch Filter:
#################################################################
log4perl.filter.M1 = Log::Log4perl::Filter::LevelMatch
log4perl.filter.M1.LevelToMatch = INFO
log4perl.filter.M1.AcceptOnMatch = true
DESCRIPTION¶
Log4perl allows the use of customized filters in its appenders to control the
output of messages. These filters might grep for certain text chunks in a
message, verify that its priority matches or exceeds a certain level or that
this is the 10th time the same message has been submitted -- and come to a
log/no log decision based upon these circumstantial facts.
Filters have names and can be specified in two different ways in the Log4perl
configuration file: As subroutines or as filter classes. Here's a simple
filter named "MyFilter" which just verifies that the oncoming
message matches the regular expression "/let this through/i":
log4perl.filter.MyFilter = sub { /let this through/i }
It exploits the fact that when the subroutine defined above is called on a
message, Perl's special $_ variable will be set to the message text
(prerendered, i.e. concatenated but not layouted) to be logged. The subroutine
is expected to return a true value if it wants the message to be logged or a
false value if doesn't.
Also, Log::Log4perl will pass a hash to the subroutine, containing all key/value
pairs that it would pass to the corresponding appender, as specified in
Log::Log4perl::Appender. Here's an example of a filter checking the priority
of the oncoming message:
log4perl.filter.MyFilter = sub { \
my %p = @_; \
if($p{log4p_level} eq "WARN" or \
$p{log4p_level} eq "INFO") { \
return 1; \
} \
return 0; \
}
If the message priority equals "WARN" or "INFO", it returns
a true value, causing the message to be logged.
Predefined Filters¶
For common tasks like verifying that the message priority matches a certain
priority, there's already a set of predefined filters available. To perform an
exact level match, it's much cleaner to use Log4perl's "LevelMatch"
filter instead:
log4perl.filter.M1 = Log::Log4perl::Filter::LevelMatch
log4perl.filter.M1.LevelToMatch = INFO
log4perl.filter.M1.AcceptOnMatch = true
This will let the message through if its priority is INFO and suppress it
otherwise. The statement can be negated by saying
log4perl.filter.M1.AcceptOnMatch = false
instead. This way, the message will be logged if its priority is anything but
INFO.
On a similar note, Log4perl's "StringMatch" filter will check the
oncoming message for strings or regular expressions:
log4perl.filter.M1 = Log::Log4perl::Filter::StringMatch
log4perl.filter.M1.StringToMatch = bl.. bl..
log4perl.filter.M1.AcceptOnMatch = true
This will open the gate for messages like "blah blah" because the
regular expression in the "StringToMatch" matches them. Again, the
setting of "AcceptOnMatch" determines if the filter is defined in a
positive or negative way.
All class filter entries in the configuration file have to adhere to the
following rule: Only after a filter has been defined by name and
class/subroutine, its attribute values can be assigned, just like the
"true" value above gets assigned to the "AcceptOnMatch"
attribute
after the filter "M1" has been defined.
Attaching a filter to an appender¶
Attaching a filter to an appender is as easy as assigning its name to the
appender's "Filter" attribute:
log4perl.appender.MyAppender.Filter = MyFilter
This will cause "Log::Log4perl" to call the filter subroutine/method
every time a message is supposed to be passed to the appender. Depending on
the filter's return value, "Log::Log4perl" will either continue as
planned or withdraw immediately.
Combining filters with Log::Log4perl::Filter::Boolean¶
Sometimes, it's useful to combine the output of various filters to arrive at a
log/no log decision. While Log4j, Log4perl's mother ship, has chosen to
implement this feature as a filter chain, similar to Linux' IP chains,
Log4perl tries a different approach.
Typically, filter results will not need to be bumped along chains but combined
in a programmatic manner using boolean logic. "Log if this filter says
'yes' and that filter says 'no'" is a fairly common requirement, but hard
to implement as a chain.
"Log::Log4perl::Filter::Boolean" is a specially predefined custom
filter for Log4perl. It combines the results of other custom filters in
arbitrary ways, using boolean expressions:
log4perl.logger = WARN, AppWarn, AppError
log4perl.filter.Match1 = sub { /let this through/ }
log4perl.filter.Match2 = sub { /and that, too/ }
log4perl.filter.MyBoolean = Log::Log4perl::Filter::Boolean
log4perl.filter.MyBoolean.logic = Match1 || Match2
log4perl.appender.Screen = Log::Log4perl::Appender::Screen
log4perl.appender.Screen.Filter = MyBoolean
log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
"Log::Log4perl::Filter::Boolean"'s boolean expressions allow for
combining different appenders by name using AND (&& or &), OR (||
or |) and NOT (!) as logical expressions. Also, parentheses can be used for
defining precedences. Operator precedence follows standard Perl conventions.
Here's a bunch of examples:
Match1 && !Match2 # Match1 and not Match2
!(Match1 || Match2) # Neither Match1 nor Match2
(Match1 && Match2) || Match3 # Both Match1 and Match2 or Match3
Writing your own filter classes¶
If none of Log::Log4perl's predefined filter classes fits your needs, you can
easily roll your own: Just define a new class, derive it from the baseclass
"Log::Log4perl::Filter", and define its "new" and
"ok" methods like this:
package Log::Log4perl::Filter::MyFilter;
use base Log::Log4perl::Filter;
sub new {
my ($class, %options) = @_;
my $self = { %options,
};
bless $self, $class;
return $self;
}
sub ok {
my ($self, %p) = @_;
# ... decide and return 1 or 0
}
1;
Log4perl will call the
ok() method to determine if the filter should let
the message pass or not. A true return value indicates the message will be
logged by the appender, a false value blocks it.
Values you've defined for its attributes in Log4perl's configuration file, will
be received through its "new" method:
log4perl.filter.MyFilter = Log::Log4perl::Filter::MyFilter
log4perl.filter.MyFilter.color = red
will cause "Log::Log4perl::Filter::MyFilter"'s constructor to be
called like this:
Log::Log4perl::Filter::MyFilter->new( name => "MyFilter",
color => "red" );
The custom filter class should use this to set the object's attributes, to have
them available later to base log/nolog decisions on it.
"ok()" is the filter's method to tell if it agrees or disagrees with
logging the message. It will be called by Log::Log4perl whenever it needs the
filter to decide. A false value returned by "ok()" will block
messages, a true value will let them through.
A Practical Example: Level Matching¶
See Log::Log4perl::FAQ for this.
SEE ALSO¶
Log::Log4perl::Filter::LevelMatch, Log::Log4perl::Filter::LevelRange,
Log::Log4perl::Filter::StringRange, Log::Log4perl::Filter::Boolean
COPYRIGHT AND LICENSE¶
Copyright 2002-2009 by Mike Schilli <m@perlmeister.com> and Kevin Goess
<cpan@goess.org>.
This library is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.