Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Log-Dispatch CPAN distribution.

Report information
The Basics
Id: 40561
Status: resolved
Priority: 0/
Queue: Log-Dispatch

People
Owner: Nobody in particular
Requestors: steve [...] opensauce.de
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 2.21
Fixed in: 2.23



Subject: dispatch disregards individual output level settings
My understanding is that each output specifies which levels it accepts and should only be given valid messages. In Log::Dispatch 2.21 the log method only checks if ANY of the outputs will accept the new message. This results in messages appearing in outputs in which they should not be expected. Log::Dispatch::log checks logging levels across all outputs. If the check succeeds, it then calls _log_to() which sends the message to all outputs regardless of their individual min_level and/or max_level settings. This can be fixed by adding a _should_log() check in Log::Dispatch::_log_to() before sending the message to each output (see patch) I've also included a simple test script which demonstrates this problem. Steve
Subject: Log.t
#!/usr/bin/perl use strict; use warnings; use YAML; use Test::More; use FindBin qw( $RealBin ); use lib "$RealBin/../../lib"; use SDE::Log plan( 'tests' => 21 ); my $dispatcher = SDE::Log->dispatcher(); $dispatcher->add( LogTester->new( 'name' => 'debug', 'min_level' => 'debug', 'max_level' => 'info', ) ); $dispatcher->add( LogTester->new( 'name' => 'runtime', 'min_level' => 'warning', 'max_level' => 'critical', ) ); isa_ok( $dispatcher, 'Log::Dispatch', 'Expect a Log::Dispatch object' ); ok( $dispatcher->would_log( 'debug' ), 'debug should not be logged' ); ok( $dispatcher->would_log( 'info' ), 'info should not be logged' ); ok( ! $dispatcher->would_log( 'notice' ), 'notice should not be logged' ); ok( $dispatcher->would_log( 'warning' ), 'warning should be logged' ); ok( $dispatcher->would_log( 'error' ), 'error should be logged' ); ok( $dispatcher->would_log( 'critical' ), 'critical should be logged' ); ok( ! $dispatcher->would_log( 'alert' ), 'alert should not be logged' ); ok( ! $dispatcher->would_log( 'emergency' ), 'emergency should not be logged' ); $dispatcher->log( 'level' => 'debug', 'message' => 'debug message' ); $dispatcher->log( 'level' => 'info', 'message' => 'info message' ); $dispatcher->log( 'level' => 'notice', 'message' => 'notice message' ); $dispatcher->log( 'level' => 'warning', 'message' => 'warning message' ); $dispatcher->log( 'level' => 'error', 'message' => 'error message' ); $dispatcher->log( 'level' => 'critical', 'message' => 'critical message' ); $dispatcher->log( 'level' => 'alert', 'message' => 'alert message' ); $dispatcher->log( 'level' => 'emergency', 'message' => 'emergency message' ); my @debug_messages = $dispatcher->output( 'debug' )->messages(); is( $#debug_messages, 1, 'two debugging messages' ); is( $debug_messages[0]{'level'}, 'debug', 'first debug message should have the level: debug' ); is( $debug_messages[0]{'message'}, 'debug message', 'first debug message should have been a debug message' ); is( $debug_messages[1]{'level'}, 'info', 'second debug message should have the level: info' ); is( $debug_messages[1]{'message'}, 'info message', 'second debug message should have been an info message' ); my @runtime_messages = $dispatcher->output( 'runtime' )->messages(); is( $#runtime_messages, 2, 'three runtime messages' ); is( $runtime_messages[0]{'level'}, 'warning', 'first runtime message should have the level: debug' ); is( $runtime_messages[0]{'message'}, 'warning message', 'first runtime message should have been a debug message' ); is( $runtime_messages[1]{'level'}, 'error', 'second runtime message should have the level: error' ); is( $runtime_messages[1]{'message'}, 'error message', 'second runtime message should have been an error message' ); is( $runtime_messages[2]{'level'}, 'critical', 'third runtime message should have the level: critical' ); is( $runtime_messages[2]{'message'}, 'critical message', 'third runtime message should have been a critical message' ); exit( 0 ); package LogTester; use YAML; use Log::Dispatch::Output; use base qw( Log::Dispatch::Output ); sub new { my $class = shift; my $self = bless {}, $class; $self->_basic_init( @_ ); $self->{'messages'} = []; return $self; } sub log { my $self = shift; my $message = { @_ }; push( @{$self->{'messages'}}, $message ); } sub messages { my $self = shift; return @{$self->{'messages'}}; }
Subject: level_check.patch
diff --git a/lib/Log/Dispatch.pm b/lib/Log/Dispatch.pm index 0ad463c..a98f041 100755 --- a/lib/Log/Dispatch.pm +++ b/lib/Log/Dispatch.pm @@ -146,7 +146,7 @@ sub _log_to if (exists $self->{outputs}{$name}) { - $self->{outputs}{$name}->log(@_); + $self->{outputs}{$name}->log(@_) if $self->{outputs}{$name}->_should_log($p{level}); } elsif ($^W) {
From: steve [...] opensauce.de
oops - uploaded the wrong version of Log.t This one uses Log::Dispatch instead of my derived class.
#!/usr/bin/perl use strict; use warnings; use YAML; use Test::More; use Log::Dispatch; plan( 'tests' => 21 ); my $dispatcher = Log::Dispatch->new(); $dispatcher->add( LogTester->new( 'name' => 'debug', 'min_level' => 'debug', 'max_level' => 'info', ) ); $dispatcher->add( LogTester->new( 'name' => 'runtime', 'min_level' => 'warning', 'max_level' => 'critical', ) ); isa_ok( $dispatcher, 'Log::Dispatch', 'Expect a Log::Dispatch object' ); ok( $dispatcher->would_log( 'debug' ), 'debug should not be logged' ); ok( $dispatcher->would_log( 'info' ), 'info should not be logged' ); ok( ! $dispatcher->would_log( 'notice' ), 'notice should not be logged' ); ok( $dispatcher->would_log( 'warning' ), 'warning should be logged' ); ok( $dispatcher->would_log( 'error' ), 'error should be logged' ); ok( $dispatcher->would_log( 'critical' ), 'critical should be logged' ); ok( ! $dispatcher->would_log( 'alert' ), 'alert should not be logged' ); ok( ! $dispatcher->would_log( 'emergency' ), 'emergency should not be logged' ); $dispatcher->log( 'level' => 'debug', 'message' => 'debug message' ); $dispatcher->log( 'level' => 'info', 'message' => 'info message' ); $dispatcher->log( 'level' => 'notice', 'message' => 'notice message' ); $dispatcher->log( 'level' => 'warning', 'message' => 'warning message' ); $dispatcher->log( 'level' => 'error', 'message' => 'error message' ); $dispatcher->log( 'level' => 'critical', 'message' => 'critical message' ); $dispatcher->log( 'level' => 'alert', 'message' => 'alert message' ); $dispatcher->log( 'level' => 'emergency', 'message' => 'emergency message' ); my @debug_messages = $dispatcher->output( 'debug' )->messages(); is( $#debug_messages, 1, 'two debugging messages' ); is( $debug_messages[0]{'level'}, 'debug', 'first debug message should have the level: debug' ); is( $debug_messages[0]{'message'}, 'debug message', 'first debug message should have been a debug message' ); is( $debug_messages[1]{'level'}, 'info', 'second debug message should have the level: info' ); is( $debug_messages[1]{'message'}, 'info message', 'second debug message should have been an info message' ); my @runtime_messages = $dispatcher->output( 'runtime' )->messages(); is( $#runtime_messages, 2, 'three runtime messages' ); is( $runtime_messages[0]{'level'}, 'warning', 'first runtime message should have the level: debug' ); is( $runtime_messages[0]{'message'}, 'warning message', 'first runtime message should have been a debug message' ); is( $runtime_messages[1]{'level'}, 'error', 'second runtime message should have the level: error' ); is( $runtime_messages[1]{'message'}, 'error message', 'second runtime message should have been an error message' ); is( $runtime_messages[2]{'level'}, 'critical', 'third runtime message should have the level: critical' ); is( $runtime_messages[2]{'message'}, 'critical message', 'third runtime message should have been a critical message' ); exit( 0 ); package LogTester; use YAML; use Log::Dispatch::Output; use base qw( Log::Dispatch::Output ); sub new { my $class = shift; my $self = bless {}, $class; $self->_basic_init( @_ ); $self->{'messages'} = []; return $self; } sub log { my $self = shift; my $message = { @_ }; push( @{$self->{'messages'}}, $message ); } sub messages { my $self = shift; return @{$self->{'messages'}}; }
On Fri Oct 31 07:05:54 2008, cobber wrote: Show quoted text
> My understanding is that each output specifies which levels it accepts > and should only be given valid messages. In Log::Dispatch 2.21 the log > method only checks if ANY of the outputs will accept the new message. > This results in messages appearing in outputs in which they should not > be expected. > > Log::Dispatch::log checks logging levels across all outputs. > If the check succeeds, it then calls _log_to() which sends the message > to all outputs regardless of their individual min_level and/or max_level > settings. > > This can be fixed by adding a _should_log() check in > Log::Dispatch::_log_to() before sending the message to each output (see > patch) > > I've also included a simple test script which demonstrates this problem.
If you look at the log() method in Log::Dispatch::Output, you'll see that it handles this. When you make a custom output, you need to provide a log_message method, not override log.
I'm marking this resolved. If you have further questions, please reply to me directly, as replying to this ticket will re-open it.
Subject: Re: [rt.cpan.org #40561] dispatch disregards individual output level settings
Date: Wed, 12 Nov 2008 11:01:47 +0100
To: bug-Log-Dispatch [...] rt.cpan.org
From: Stephen Riehm <steve [...] opensauce.de>
Hi Dave, Show quoted text
> I'm marking this resolved. If you have further questions, please reply > to me directly, as replying to this ticket will re-open it.
Thanks for taking the time to look at this issue. Of course you're right, (I just changed log() to log_message() in my test case and it works fine), however, I re-traced what I did and discovered the cause for my derailment. In Log/Dispatch.pm it states: Making your own logging objects Making your own logging object is generally as simple as subclassing Log::Dispatch::Output and overriding the "new" and "log" methods. See the Log::Dispatch::Output docs for more details. (which of course, I did ;-) Also, when you look at the documentation for Log::Dispatch::Output, only the public methods are described in detail. So, here's a different small patch that I'd like to suggest for the next release, changing "log" to "log_message" in the above sentence in Log/Dispatch.pm and making the subclassing details in Log/Dispatch/ Output.pm a bit clearer. (see attached patch file).
Download _patch
application/octet-stream 1.6k

Message body not shown because it is not plain text.

PS: I noticed that you updated Log::Dispatch::Output since I reported this issue - it's a start, but its right at the very bottom of the file and contradicts the information from Log::Dispatch. Thanks, Steve