File Coverage

blib/lib/Log/Dispatch/Output.pm
Criterion Covered Total %
statement 65 79 82.2
branch 12 20 60.0
condition 5 9 55.5
subroutine 18 21 85.7
pod 5 6 83.3
total 105 135 77.7


line stmt bran cond sub pod time code
1             package Log::Dispatch::Output;
2              
3 29     29   262 use strict;
  29         59  
  29         1094  
4 29     29   170 use warnings;
  29         61  
  29         1497  
5              
6             our $VERSION = '2.70';
7              
8 29     29   170 use Carp ();
  29         55  
  29         722  
9 29     29   167 use Try::Tiny;
  29         39  
  29         1972  
10 29     29   614 use Log::Dispatch;
  29         257  
  29         771  
11 29     29   173 use Log::Dispatch::Types;
  29         60  
  29         212  
12 29     29   826633 use Log::Dispatch::Vars qw( @OrderedLevels );
  29         105  
  29         4220  
13 29     29   233 use Params::ValidationCompiler qw( validation_for );
  29         80  
  29         1460  
14              
15 29     29   227 use base qw( Log::Dispatch::Base );
  29         82  
  29         31953  
16              
17             sub new {
18 0     0 0 0 my $proto = shift;
19 0   0     0 my $class = ref $proto || $proto;
20              
21 0         0 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 3     3 1 19 my $self = shift;
40 3         80 my %p = $validator->(@_);
41              
42 3         109 my $level_num = $self->_level_as_number( $p{level} );
43 3 50       9 return unless $self->_should_log($level_num);
44              
45 3         18 local $! = undef;
46             $p{message} = $self->_apply_callbacks(%p)
47 3 50       9 if $self->{callbacks};
48              
49 3         13 $self->log_message(%p);
50             }
51              
52             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
53             sub _log_with_num {
54 132     132   336 my $self = shift;
55 132         346 my $level_num = shift;
56 132         345 my %p = @_;
57              
58 132 100       446 return unless $self->_should_log($level_num);
59              
60 131         2510 local $! = undef;
61             $p{message} = $self->_apply_callbacks(%p)
62 131 100       1107 if $self->{callbacks};
63              
64 131         842 $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 107     107   577 my $self = shift;
99 107         2825 my %p = $validator->(@_);
100              
101 107         4569 $self->{level_names} = \@OrderedLevels;
102              
103 107   66     940 $self->{name} = $p{name} || $self->_unique_name();
104              
105 107         1046 $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 107 100       284 : $#{ $self->{level_names} }
  91         443  
112             );
113              
114 107 100       315 $self->{callbacks} = $p{callbacks} if $p{callbacks};
115              
116 107 100       307 if ( $p{newline} ) {
117 57         100 push @{ $self->{callbacks} }, \&_add_newline_callback;
  57         442  
118             }
119             }
120             }
121              
122             sub name {
123 214     214 1 353 my $self = shift;
124              
125 214         985 return $self->{name};
126             }
127              
128             sub min_level {
129 0     0 1 0 my $self = shift;
130              
131 0         0 return $self->{level_names}[ $self->{min_level} ];
132             }
133              
134             sub max_level {
135 1     1 1 3 my $self = shift;
136              
137 1         5 return $self->{level_names}[ $self->{max_level} ];
138             }
139              
140             sub accepted_levels {
141 1     1 1 12 my $self = shift;
142              
143 1         6 return @{ $self->{level_names} }
144 1         4 [ $self->{min_level} .. $self->{max_level} ];
145             }
146              
147             sub _should_log {
148 363     363   634 my $self = shift;
149 363         708 my $level_num = shift;
150              
151             return ( ( $level_num >= $self->{min_level} )
152 363   100     3208 && ( $level_num <= $self->{max_level} ) );
153             }
154              
155             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
156             sub _level_as_name {
157 0     0   0 my $self = shift;
158 0         0 my $level = shift;
159              
160 0 0       0 unless ( defined $level ) {
161 0         0 Carp::croak 'undefined value provided for log level';
162             }
163              
164 0         0 my $canonical_level;
165 0 0       0 unless ( $canonical_level = Log::Dispatch->level_is_valid($level) ) {
166 0         0 Carp::croak "$level is not a valid Log::Dispatch log level";
167             }
168              
169 0 0       0 return $canonical_level unless $level =~ /\A[0-7]+\z/;
170              
171 0         0 return $self->{level_names}[$level];
172             }
173             ## use critic
174              
175             my $_unique_name_counter = 0;
176              
177             sub _unique_name {
178 54     54   131 my $self = shift;
179              
180 54         604 return '_anon_' . $_unique_name_counter++;
181             }
182              
183             sub _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 69     69   488 +{@_}->{message} . "\n";
188             }
189              
190             1;
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              
202             Log::Dispatch::Output - Base class for all Log::Dispatch::* objects
203              
204             =head1 VERSION
205              
206             version 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              
241             This module is the base class from which all Log::Dispatch::* objects
242             should be derived.
243              
244             =head1 CONSTRUCTOR
245              
246             The constructor, C<new>, must be overridden in a subclass. See L<Output
247             Classes|Log::Dispatch/OUTPUT CLASSES> for a description of the common
248             parameters accepted by this constructor.
249              
250             =head1 METHODS
251              
252             This class provides the following methods:
253              
254             =head2 $output->_basic_init(%p)
255              
256             This should be called from a subclass's constructor. Make sure to
257             pass the arguments in @_ to it. It sets the object's name and minimum
258             level from the passed parameters It also sets up two other attributes which
259             are used by other Log::Dispatch::Output methods, level_names and level_numbers.
260             Subclasses will perform parameter validation in this method, and must also call
261             the superclass's method.
262              
263             =head2 $output->name
264              
265             Returns the object's name.
266              
267             =head2 $output->min_level
268              
269             Returns the object's minimum log level.
270              
271             =head2 $output->max_level
272              
273             Returns the object's maximum log level.
274              
275             =head2 $output->accepted_levels
276              
277             Returns a list of the object's accepted levels (by name) from minimum
278             to maximum.
279              
280             =head2 $output->log( level => $, message => $ )
281              
282             Sends a message if the level is greater than or equal to the object's
283             minimum level. This method applies any message formatting callbacks
284             that the object may have.
285              
286             =head2 $output->_should_log ($)
287              
288             This method is called from the C<log()> method with the log level of
289             the message to be logged as an argument. It returns a boolean value
290             indicating whether or not the message should be logged by this
291             particular object. The C<log()> method will not process the message
292             if the return value is false.
293              
294             =head2 $output->_level_as_number ($)
295              
296             This method will take a log level as a string (or a number) and return
297             the number of that log level. If not given an argument, it returns
298             the calling object's log level instead. If it cannot determine the
299             level then it will croak.
300              
301             =head2 $output->add_callback( $code )
302              
303             Adds a callback (like those given during construction). It is added to the end
304             of the list of callbacks.
305              
306             =head2 $dispatch->remove_callback( $code )
307              
308             Remove the given callback from the list of callbacks.
309              
310             =head1 SUBCLASSING
311              
312             This class should be used as the base class for all logging objects
313             you create that you would like to work under the Log::Dispatch
314             architecture. Subclassing is fairly trivial. For most subclasses, if
315             you simply copy the code in the SYNOPSIS and then put some
316             functionality into the C<log_message> method then you should be all
317             set. Please make sure to use the C<_basic_init> method as described above.
318              
319             The actual logging implementation should be done in a C<log_message>
320             method that you write. B<Do not override C<log>!>.
321              
322             =head1 SUPPORT
323              
324             Bugs may be submitted at L<https://github.com/houseabsolute/Log-Dispatch/issues>.
325              
326             I am also usually active on IRC as 'autarch' on C<irc://irc.perl.org>.
327              
328             =head1 SOURCE
329              
330             The source code repository for Log-Dispatch can be found at L<https://github.com/houseabsolute/Log-Dispatch>.
331              
332             =head1 AUTHOR
333              
334             Dave Rolsky <autarch@urth.org>
335              
336             =head1 COPYRIGHT AND LICENSE
337              
338             This software is Copyright (c) 2020 by Dave Rolsky.
339              
340             This is free software, licensed under:
341              
342             The Artistic License 2.0 (GPL Compatible)
343              
344             The full text of the license can be found in the
345             F<LICENSE> file included with this distribution.
346              
347             =cut