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   234 use strict;
  29         58  
  29         962  
4 29     29   154 use warnings;
  29         173  
  29         1076  
5              
6             our $VERSION = '2.71';
7              
8 29     29   157 use Carp ();
  29         57  
  29         457  
9 29     29   143 use Try::Tiny;
  29         55  
  29         2068  
10 29     29   716 use Log::Dispatch;
  29         112  
  29         639  
11 29     29   153 use Log::Dispatch::Types;
  29         75  
  29         178  
12 29     29   808257 use Log::Dispatch::Vars qw( @OrderedLevels );
  29         86  
  29         3218  
13 29     29   231 use Params::ValidationCompiler qw( validation_for );
  29         83  
  29         1462  
14              
15 29     29   231 use base qw( Log::Dispatch::Base );
  29         55  
  29         37777  
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         75 my %p = $validator->(@_);
41              
42 3         98 my $level_num = $self->_level_as_number( $p{level} );
43 3 50       18 return unless $self->_should_log($level_num);
44              
45 3         21 local $! = undef;
46             $p{message} = $self->_apply_callbacks(%p)
47 3 50       14 if $self->{callbacks};
48              
49 3         24 $self->log_message(%p);
50             }
51              
52             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
53             sub _log_with_num {
54 132     132   333 my $self = shift;
55 132         258 my $level_num = shift;
56 132         375 my %p = @_;
57              
58 132 100       433 return unless $self->_should_log($level_num);
59              
60 131         2919 local $! = undef;
61             $p{message} = $self->_apply_callbacks(%p)
62 131 100       1578 if $self->{callbacks};
63              
64 131         999 $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   659 my $self = shift;
99 107         3248 my %p = $validator->(@_);
100              
101 107         5159 $self->{level_names} = \@OrderedLevels;
102              
103 107   66     755 $self->{name} = $p{name} || $self->_unique_name();
104              
105 107         1163 $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       308 : $#{ $self->{level_names} }
  91         325  
112             );
113              
114 107 100       291 $self->{callbacks} = $p{callbacks} if $p{callbacks};
115              
116 107 100       323 if ( $p{newline} ) {
117 57         101 push @{ $self->{callbacks} }, \&_add_newline_callback;
  57         564  
118             }
119             }
120             }
121              
122             sub name {
123 214     214 1 369 my $self = shift;
124              
125 214         1231 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 4 my $self = shift;
136              
137 1         6 return $self->{level_names}[ $self->{max_level} ];
138             }
139              
140             sub accepted_levels {
141 1     1 1 12 my $self = shift;
142              
143 1         5 return @{ $self->{level_names} }
144 1         4 [ $self->{min_level} .. $self->{max_level} ];
145             }
146              
147             sub _should_log {
148 363     363   850 my $self = shift;
149 363         725 my $level_num = shift;
150              
151             return ( ( $level_num >= $self->{min_level} )
152 363   100     4547 && ( $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   128 my $self = shift;
179              
180 54         579 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   658 +{@_}->{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.71
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 should be
242             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 pass the
257             arguments in @_ to it. It sets the object's name and minimum level from the
258             passed parameters It also sets up two other attributes which are used by other
259             Log::Dispatch::Output methods, level_names and level_numbers. Subclasses will
260             perform parameter validation in this method, and must also call the
261             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 to
278             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 minimum
283             level. This method applies any message formatting callbacks that the object may
284             have.
285              
286             =head2 $output->_should_log ($)
287              
288             This method is called from the C<log()> method with the log level of the
289             message to be logged as an argument. It returns a boolean value indicating
290             whether or not the message should be logged by this particular object. The
291             C<log()> method will not process the message if the return value is false.
292              
293             =head2 $output->_level_as_number ($)
294              
295             This method will take a log level as a string (or a number) and return the
296             number of that log level. If not given an argument, it returns the calling
297             object's log level instead. If it cannot determine the level then it will
298             croak.
299              
300             =head2 $output->add_callback( $code )
301              
302             Adds a callback (like those given during construction). It is added to the end
303             of the list of callbacks.
304              
305             =head2 $dispatch->remove_callback( $code )
306              
307             Remove the given callback from the list of callbacks.
308              
309             =head1 SUBCLASSING
310              
311             This class should be used as the base class for all logging objects you create
312             that you would like to work under the Log::Dispatch architecture. Subclassing
313             is fairly trivial. For most subclasses, if you simply copy the code in the
314             SYNOPSIS and then put some functionality into the C<log_message> method then
315             you should be all set. Please make sure to use the C<_basic_init> method as
316             described above.
317              
318             The actual logging implementation should be done in a C<log_message> method
319             that you write. B<Do not override C<log>!>.
320              
321             =head1 SUPPORT
322              
323             Bugs may be submitted at L<https://github.com/houseabsolute/Log-Dispatch/issues>.
324              
325             =head1 SOURCE
326              
327             The source code repository for Log-Dispatch can be found at L<https://github.com/houseabsolute/Log-Dispatch>.
328              
329             =head1 AUTHOR
330              
331             Dave Rolsky <autarch@urth.org>
332              
333             =head1 COPYRIGHT AND LICENSE
334              
335             This software is Copyright (c) 2023 by Dave Rolsky.
336              
337             This is free software, licensed under:
338              
339             The Artistic License 2.0 (GPL Compatible)
340              
341             The full text of the license can be found in the
342             F<LICENSE> file included with this distribution.
343              
344             =cut