File Coverage

blib/lib/MojoX/Log/Dispatch/Simple.pm
Criterion Covered Total %
statement 17 69 24.6
branch 0 8 0.0
condition 0 8 0.0
subroutine 6 42 14.2
pod 3 32 9.3
total 26 159 16.3


line stmt bran cond sub pod time code
1             # ABSTRACT: Simple Log::Dispatch replacement of Mojo::Log
2              
3             use 5.010;
4 1     1   332730 use strict;
  1         10  
5 1     1   5 use warnings;
  1         1  
  1         17  
6 1     1   4  
  1         1  
  1         20  
7             use Mojo::Base 'Mojo::EventEmitter';
8 1     1   355 use Mojo::Util 'encode';
  1         115096  
  1         5  
9 1     1   1358  
  1         2  
  1         1330  
10             our $VERSION = '1.12'; # VERSION
11              
12             has history => sub { [] };
13             has level => 'debug';
14             has max_history_size => 10;
15             has dispatch => undef;
16             has format_cb => undef;
17             has parent => undef;
18              
19             has 'path';
20             has color => sub { $ENV{MOJO_LOG_COLOR} };
21             has short => sub { $ENV{MOJO_LOG_SHORT} };
22             has handle => sub {
23             return \*STDERR unless my $path = shift->path;
24             return Mojo::File->new($path)->open('>>');
25             };
26              
27             my $self = shift->SUPER::new(@_);
28             $self->on( message => sub {
29 1     1 1 130 my ( $self, $level ) = ( shift, shift );
30             return unless ( $self->_active_level($level) );
31 0     0   0  
32 0 0       0 push( @{ $self->history }, [ time, $level, @_ ] );
33             shift @{ $self->history } while ( @{ $self->history } > $self->max_history_size );
34 0         0  
  0         0  
35 0         0 ( $self->parent // $self )->dispatch->log(
  0         0  
  0         0  
36             level => $level,
37             message => encode( 'UTF-8', $_ ),
38             ) for (@_);
39             } );
40 0   0     0 return $self;
41 1         18 }
42 1         12  
43             my ( $self, $level, @input ) = @_;
44             $self->emit( 'message', $level, ref $input[0] eq 'CODE' ? $input[0]() : @input );
45             }
46 0     0      
47 0 0         {
48             my $levels = {
49             debug => 1,
50             info => 2,
51             warn => 3,
52             error => 4,
53             fatal => 5,
54              
55             notice => 2,
56             warning => 3,
57             critical => 4,
58             alert => 5,
59             emergency => 5,
60             emerg => 5,
61              
62             err => 4,
63             crit => 4,
64             };
65              
66             my ( $self, $level ) = @_;
67             return ( $levels->{$level} >= $levels->{ $ENV{MOJO_LOG_LEVEL} || $self->level } ) ? 1 : 0;
68             }
69              
70 0     0     my ( $self, $c ) = ( shift, shift );
71 0 0 0        
72             for my $level ( (@_) ? @_ : keys %$levels ) {
73             $c->helper( $level => sub {
74             my ($self) = shift;
75 0     0 1   $self->app->log->$level($_) for (@_);
76             return;
77 0 0         } );
78             }
79 0     0      
80 0           return $self;
81 0           }
82 0           }
83              
84             my ( $self, $str ) = @_;
85 0           return $self->new( parent => $self, context => $str, level => $self->level );
86             }
87              
88             my ($self) = @_;
89             return $self->format_cb || sub { localtime(shift) . ' [' . shift() . '] ' . join( "\n", @_, '' ) };
90 0     0 0   }
91 0            
92              
93              
94              
95 0     0 0    
96 0   0 0      
  0            
97              
98              
99 0     0 0   1;
100 0     0 0    
101 0     0 0   =pod
102 0     0 1    
103 0     0 0   =encoding UTF-8
104              
105 0     0 0   =head1 NAME
106 0     0 0    
107 0     0 0   MojoX::Log::Dispatch::Simple - Simple Log::Dispatch replacement of Mojo::Log
108 0     0 0    
109 0     0 0   =head1 VERSION
110 0     0 0    
111             version 1.12
112 0     0 0    
113 0     0 0   =for markdown [![test](https://github.com/gryphonshafer/MojoX-Log-Dispatch-Simple/workflows/test/badge.svg)](https://github.com/gryphonshafer/MojoX-Log-Dispatch-Simple/actions?query=workflow%3Atest)
114             [![codecov](https://codecov.io/gh/gryphonshafer/MojoX-Log-Dispatch-Simple/graph/badge.svg)](https://codecov.io/gh/gryphonshafer/MojoX-Log-Dispatch-Simple)
115 0     0 0    
116 0     0 0   =head1 SYNOPSIS
117 0     0 0    
118 0     0 0   # from inside your startup() most likely...
119 0     0 0    
120             use Log::Dispatch;
121 0     0 0   use MojoX::Log::Dispatch::Simple;
122 0     0 0    
123 0     0 0   my $mojo_logger = MojoX::Log::Dispatch::Simple->new(
124 0     0 0   dispatch => Log::Dispatch->new,
125 0     0 0   level => 'debug'
126 0     0 0   );
127              
128 0     0 0   my ($self) = @_; # Mojolicious object from inside startup()
129 0     0 0   $self->log($mojo_logger);
130              
131 0     0 0   # ...then later inside a controller...
132 0     0 0    
133             $self->app->log->debug('Debug-level message');
134             $self->app->log->info('Info-level message');
135              
136             # ...or back to your startup() to setup some helpers...
137              
138             $mojo_logger->helpers($self);
139             $mojo_logger->helpers( $self, qw( debug info warn error ) );
140              
141             # ...so that in your controllers you can...
142              
143             $self->debug('Debug-level message');
144             $self->info('Info-level message');
145              
146             # ...or do it all at once, in the startup() most likely...
147              
148             $self->log( MojoX::Log::Dispatch::Simple->new(
149             dispatch => Log::Dispatch->new,
150             level => 'debug'
151             )->helpers($self) );
152              
153             =head1 DESCRIPTION
154              
155             This module provides a really simple way to replace the built-in L<Mojo::Log>
156             with a L<Log::Dispatch> object, and yet still support all the L<Mojo::Log>
157             log levels and other functionality L<Mojolicious> assumes exists. To make it
158             even easier, you can install helpers to all the log levels, all from the same
159             single line of code.
160              
161             $self->log( MojoX::Log::Dispatch::Simple->new(
162             dispatch => Log::Dispatch->new,
163             level => 'debug'
164             )->helpers($self) );
165              
166             The module tries not to make any assumptions about how you want to use
167             L<Log::Dispatch>. In fact, you can if desired use an alternate L<Log::Dispatch>
168             library so long as it offers a similar interface.
169              
170             =head1 PRIMARY METHODS
171              
172             These are methods that you would likely use from within your L<Mojolicious>
173             C<startup()> subroutine.
174              
175             =head2 new
176              
177             This method instantiates an object. It requires a "dispatch" parameter, which
178             should be a L<Log::Dispatch> object (or an object with a similar signature).
179             The method allow accepts an optional "level" parameter, which is used to set
180             the log level for your L<Mojolicious> application.
181              
182             my $mojo_logger = MojoX::Log::Dispatch::Simple->new(
183             dispatch => Log::Dispatch->new,
184             level => 'debug'
185             );
186              
187             Optionally, you can also provide a "format_cb" value, which should be a
188             reference to a subroutine that will be used to provide custom formatting to
189             entries that appear on the L<Mojolicious> error reporting web page. This
190             formatting will have nothing at all to do with whatever your L<Log::Dispatch>
191             does; it only formats log entries that appear on the L<Mojolicious> error
192             reporting web page.
193              
194             my $mojo_logger = MojoX::Log::Dispatch::Simple->new(
195             dispatch => Log::Dispatch->new,
196             level => 'debug',
197             format_cb => sub {
198             localtime(shift) . ' [' . shift() . '] ' . join( "\n", @_, '' )
199             },
200             );
201              
202             By default, when you're looking at one of these L<Mojolicious> error reporting
203             web pages, you'll see the past 10 log entries listed. You can change that
204             by passing in a "max_history_size" value.
205              
206             my $mojo_logger = MojoX::Log::Dispatch::Simple->new(
207             dispatch => Log::Dispatch->new,
208             max_history_size => 20,
209             );
210              
211             =head2 helpers
212              
213             You can optionally tell this library to create helpers to each of the log
214             levels, or to a selection of them. This method requires that you pass in
215             a reference to the L<Mojolicious> object. If that's all you pass in, the
216             method will create a helper for every log level.
217              
218             # from inside your startup()...
219             $mojo_logger->helpers($mojo_obj);
220              
221             # now later from inside a controller...
222             $c->debug('Debug message');
223              
224             $c->app->log->debug("This is what you'd have to type without the helper");
225              
226             You can optionally pass in the names of the log levels you want helpers created
227             for, and the method will only create methods for those levels.
228              
229             $mojo_logger->helpers( $mojo_obj, qw( debug info warn ) );
230              
231             =head1 LOG LEVELS
232              
233             Unfortunately, L<Mojolicious> and L<Log::Dispatch> have somewhat different
234             ideas as to what log levels should exist. Since this module is a bridge between
235             them, it attempts to support all levels from both sides. That being said, when
236             calling log levels in your application, you will probably want to only use
237             the log levels from L<Log::Dispatch> if you use your L<Log::Dispatch> code
238             in non-Mojo-app areas of your ecosystem, thus keeping things uniform everywhere.
239              
240             For the purposes of understanding log levels relative to each other, all log
241             levels are assigned a "rank" value. Since L<Mojolicious> has fewer levels than
242             L<Log::Dispatch> and there are 5 of them, a level's "rank" is an integer
243             between 1 and 5.
244              
245             =head2 Log::Dispatch Log Levels
246              
247             The following are L<Log::Dispatch> log levels along with their corresponding
248             "rank" integer and any supported aliases:
249              
250             =over 4
251              
252             =item *
253              
254             debug (1)
255              
256             =item *
257              
258             info (2)
259              
260             =item *
261              
262             notice (2)
263              
264             =item *
265              
266             warning, warn (3)
267              
268             =item *
269              
270             error, err (4)
271              
272             =item *
273              
274             critical, crit (4)
275              
276             =item *
277              
278             alert (5)
279              
280             =item *
281              
282             emergency, emerg (5)
283              
284             =back
285              
286             =head2 Mojolicious Log Levels
287              
288             The following are L<Mojolicious> log levels along with their corresponding
289             "rank" integer and any supported aliases:
290              
291             =over 4
292              
293             =item *
294              
295             debug (1)
296              
297             =item *
298              
299             info (2)
300              
301             =item *
302              
303             warn (3)
304              
305             =item *
306              
307             error (4)
308              
309             =item *
310              
311             fatal (5)
312              
313             =back
314              
315             You can check what log level you're set at by either just reading C<$obj->level>
316             or by running an "is_*" method. For every log level, there's a corresponding
317             "is_*" method.
318              
319             my $log_level_at_or_above_notice = $obj->is_notice;
320              
321             Note that this gets somewhat confusing when dealing with L<Log::Dispatch> log
322             levels because from the perspective of L<Log::Dispatch>, the "notice" level is
323             a unique level that's lower than a "warning" and higher than the "info" level.
324             However, from the perspective of L<Mojolicious>, there's no such log level.
325             It will assume you're set at the "info" log level. Ergo, if you call
326             C<is_notice()> or C<is_info()>, you'll get the same result.
327              
328             =head1 POST-INSTANTIATION MEDDLING
329              
330             Following the creation of the object from this library, you can still
331             manipulate various attributes, which are:
332              
333             =over 4
334              
335             =item *
336              
337             dispatch (a L<Log::Dispatch> object)
338              
339             =item *
340              
341             level
342              
343             =item *
344              
345             max_history_size
346              
347             =item *
348              
349             format_cb (a subref)
350              
351             =item *
352              
353             history (an arrayref)
354              
355             =back
356              
357             So you can do things like:
358              
359             $obj->dispatch->remove('debug');
360              
361             This also means you can manipulate the log history. Why you'd ever want to do
362             that, I can't say; but you can. Freedom is messy.
363              
364             =head1 SEE ALSO
365              
366             L<Mojolicious>, L<Log::Dispatch>.
367              
368             You can also look for additional information at:
369              
370             =over 4
371              
372             =item *
373              
374             L<GitHub|https://github.com/gryphonshafer/MojoX-Log-Dispatch-Simple>
375              
376             =item *
377              
378             L<MetaCPAN|https://metacpan.org/pod/MojoX::Log::Dispatch::Simple>
379              
380             =item *
381              
382             L<GitHub Actions|https://github.com/gryphonshafer/MojoX-Log-Dispatch-Simple/actions>
383              
384             =item *
385              
386             L<Codecov|https://codecov.io/gh/gryphonshafer/MojoX-Log-Dispatch-Simple>
387              
388             =item *
389              
390             L<CPANTS|http://cpants.cpanauthors.org/dist/MojoX-Log-Dispatch-Simple>
391              
392             =item *
393              
394             L<CPAN Testers|http://www.cpantesters.org/distro/M/MojoX-Log-Dispatch-Simple.html>
395              
396             =back
397              
398             =for Pod::Coverage alert crit critical debug emerg emergency err fatal format info is_alert is_crit is_critical is_debug is_emerg is_emergency is_err is_error is_fatal is_info is_notice is_warn is_warning notice warn warning context is_level trace
399              
400             =head1 GRATITUDE
401              
402             Special thanks to the following for contributing to this module:
403              
404             =over 4
405              
406             =item *
407              
408             Tomohiro Hosaka
409              
410             =back
411              
412             =head1 AUTHOR
413              
414             Gryphon Shafer <gryphon@cpan.org>
415              
416             =head1 COPYRIGHT AND LICENSE
417              
418             This software is Copyright (c) 2015-2050 by Gryphon Shafer.
419              
420             This is free software, licensed under:
421              
422             The Artistic License 2.0 (GPL Compatible)
423              
424             =cut
425              
426