File Coverage

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


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