1package Log::Dispatch::Output; 2 3use strict; 4use warnings; 5 6our $VERSION = '2.70'; 7 8use Carp (); 9use Try::Tiny; 10use Log::Dispatch; 11use Log::Dispatch::Types; 12use Log::Dispatch::Vars qw( @OrderedLevels ); 13use Params::ValidationCompiler qw( validation_for ); 14 15use base qw( Log::Dispatch::Base ); 16 17sub new { 18 my $proto = shift; 19 my $class = ref $proto || $proto; 20 21 die "The new method must be overridden in the $class subclass"; 22} 23 24{ 25 my $validator = validation_for( 26 params => { 27 level => { type => t('LogLevel') }, 28 29 # Pre-PVC we accepted empty strings, which is weird, but we don't 30 # want to break back-compat. See 31 # https://github.com/houseabsolute/Log-Dispatch/issues/38. 32 message => { type => t('Str') }, 33 }, 34 slurpy => 1, 35 ); 36 37 ## no critic (Subroutines::ProhibitBuiltinHomonyms) 38 sub log { 39 my $self = shift; 40 my %p = $validator->(@_); 41 42 my $level_num = $self->_level_as_number( $p{level} ); 43 return unless $self->_should_log($level_num); 44 45 local $! = undef; 46 $p{message} = $self->_apply_callbacks(%p) 47 if $self->{callbacks}; 48 49 $self->log_message(%p); 50 } 51 52 ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines) 53 sub _log_with_num { 54 my $self = shift; 55 my $level_num = shift; 56 my %p = @_; 57 58 return unless $self->_should_log($level_num); 59 60 local $! = undef; 61 $p{message} = $self->_apply_callbacks(%p) 62 if $self->{callbacks}; 63 64 $self->log_message(%p); 65 } 66 ## use critic 67} 68 69{ 70 my $validator = validation_for( 71 params => { 72 name => { 73 type => t('NonEmptyStr'), 74 optional => 1, 75 }, 76 min_level => { type => t('LogLevel') }, 77 max_level => { 78 type => t('LogLevel'), 79 optional => 1, 80 }, 81 callbacks => { 82 type => t('Callbacks'), 83 optional => 1, 84 }, 85 newline => { 86 type => t('Bool'), 87 default => 0, 88 }, 89 }, 90 91 # This is primarily here for the benefit of outputs outside of this 92 # distro which may be passing who-knows-what to this method. 93 slurpy => 1, 94 ); 95 96 ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines) 97 sub _basic_init { 98 my $self = shift; 99 my %p = $validator->(@_); 100 101 $self->{level_names} = \@OrderedLevels; 102 103 $self->{name} = $p{name} || $self->_unique_name(); 104 105 $self->{min_level} = $self->_level_as_number( $p{min_level} ); 106 107 # Either use the parameter supplied or just the highest possible level. 108 $self->{max_level} = ( 109 exists $p{max_level} 110 ? $self->_level_as_number( $p{max_level} ) 111 : $#{ $self->{level_names} } 112 ); 113 114 $self->{callbacks} = $p{callbacks} if $p{callbacks}; 115 116 if ( $p{newline} ) { 117 push @{ $self->{callbacks} }, \&_add_newline_callback; 118 } 119 } 120} 121 122sub name { 123 my $self = shift; 124 125 return $self->{name}; 126} 127 128sub min_level { 129 my $self = shift; 130 131 return $self->{level_names}[ $self->{min_level} ]; 132} 133 134sub max_level { 135 my $self = shift; 136 137 return $self->{level_names}[ $self->{max_level} ]; 138} 139 140sub accepted_levels { 141 my $self = shift; 142 143 return @{ $self->{level_names} } 144 [ $self->{min_level} .. $self->{max_level} ]; 145} 146 147sub _should_log { 148 my $self = shift; 149 my $level_num = shift; 150 151 return ( ( $level_num >= $self->{min_level} ) 152 && ( $level_num <= $self->{max_level} ) ); 153} 154 155## no critic (Subroutines::ProhibitUnusedPrivateSubroutines) 156sub _level_as_name { 157 my $self = shift; 158 my $level = shift; 159 160 unless ( defined $level ) { 161 Carp::croak 'undefined value provided for log level'; 162 } 163 164 my $canonical_level; 165 unless ( $canonical_level = Log::Dispatch->level_is_valid($level) ) { 166 Carp::croak "$level is not a valid Log::Dispatch log level"; 167 } 168 169 return $canonical_level unless $level =~ /\A[0-7]+\z/; 170 171 return $self->{level_names}[$level]; 172} 173## use critic 174 175my $_unique_name_counter = 0; 176 177sub _unique_name { 178 my $self = shift; 179 180 return '_anon_' . $_unique_name_counter++; 181} 182 183sub _add_newline_callback { 184 185 # This weird construct is an optimization since this might be called a lot 186 # - see https://github.com/autarch/Log-Dispatch/pull/7 187 +{@_}->{message} . "\n"; 188} 189 1901; 191 192# ABSTRACT: Base class for all Log::Dispatch::* objects 193 194__END__ 195 196=pod 197 198=encoding UTF-8 199 200=head1 NAME 201 202Log::Dispatch::Output - Base class for all Log::Dispatch::* objects 203 204=head1 VERSION 205 206version 2.70 207 208=head1 SYNOPSIS 209 210 package Log::Dispatch::MySubclass; 211 212 use Log::Dispatch::Output; 213 use base qw( Log::Dispatch::Output ); 214 215 sub new { 216 my $proto = shift; 217 my $class = ref $proto || $proto; 218 219 my %p = @_; 220 221 my $self = bless {}, $class; 222 223 $self->_basic_init(%p); 224 225 # Do more if you like 226 227 return $self; 228 } 229 230 sub log_message { 231 my $self = shift; 232 my %p = @_; 233 234 # Do something with message in $p{message} 235 } 236 237 1; 238 239=head1 DESCRIPTION 240 241This module is the base class from which all Log::Dispatch::* objects 242should be derived. 243 244=head1 CONSTRUCTOR 245 246The constructor, C<new>, must be overridden in a subclass. See L<Output 247Classes|Log::Dispatch/OUTPUT CLASSES> for a description of the common 248parameters accepted by this constructor. 249 250=head1 METHODS 251 252This class provides the following methods: 253 254=head2 $output->_basic_init(%p) 255 256This should be called from a subclass's constructor. Make sure to 257pass the arguments in @_ to it. It sets the object's name and minimum 258level from the passed parameters It also sets up two other attributes which 259are used by other Log::Dispatch::Output methods, level_names and level_numbers. 260Subclasses will perform parameter validation in this method, and must also call 261the superclass's method. 262 263=head2 $output->name 264 265Returns the object's name. 266 267=head2 $output->min_level 268 269Returns the object's minimum log level. 270 271=head2 $output->max_level 272 273Returns the object's maximum log level. 274 275=head2 $output->accepted_levels 276 277Returns a list of the object's accepted levels (by name) from minimum 278to maximum. 279 280=head2 $output->log( level => $, message => $ ) 281 282Sends a message if the level is greater than or equal to the object's 283minimum level. This method applies any message formatting callbacks 284that the object may have. 285 286=head2 $output->_should_log ($) 287 288This method is called from the C<log()> method with the log level of 289the message to be logged as an argument. It returns a boolean value 290indicating whether or not the message should be logged by this 291particular object. The C<log()> method will not process the message 292if the return value is false. 293 294=head2 $output->_level_as_number ($) 295 296This method will take a log level as a string (or a number) and return 297the number of that log level. If not given an argument, it returns 298the calling object's log level instead. If it cannot determine the 299level then it will croak. 300 301=head2 $output->add_callback( $code ) 302 303Adds a callback (like those given during construction). It is added to the end 304of the list of callbacks. 305 306=head2 $dispatch->remove_callback( $code ) 307 308Remove the given callback from the list of callbacks. 309 310=head1 SUBCLASSING 311 312This class should be used as the base class for all logging objects 313you create that you would like to work under the Log::Dispatch 314architecture. Subclassing is fairly trivial. For most subclasses, if 315you simply copy the code in the SYNOPSIS and then put some 316functionality into the C<log_message> method then you should be all 317set. Please make sure to use the C<_basic_init> method as described above. 318 319The actual logging implementation should be done in a C<log_message> 320method that you write. B<Do not override C<log>!>. 321 322=head1 SUPPORT 323 324Bugs may be submitted at L<https://github.com/houseabsolute/Log-Dispatch/issues>. 325 326I am also usually active on IRC as 'autarch' on C<irc://irc.perl.org>. 327 328=head1 SOURCE 329 330The source code repository for Log-Dispatch can be found at L<https://github.com/houseabsolute/Log-Dispatch>. 331 332=head1 AUTHOR 333 334Dave Rolsky <autarch@urth.org> 335 336=head1 COPYRIGHT AND LICENSE 337 338This software is Copyright (c) 2020 by Dave Rolsky. 339 340This is free software, licensed under: 341 342 The Artistic License 2.0 (GPL Compatible) 343 344The full text of the license can be found in the 345F<LICENSE> file included with this distribution. 346 347=cut 348