File Coverage

blib/lib/Mojo/Log/Che.pm
Criterion Covered Total %
statement 59 63 93.6
branch 28 36 77.7
condition 12 19 63.1
subroutine 11 11 100.0
pod 3 3 100.0
total 113 132 85.6


line stmt bran cond sub pod time code
1             package Mojo::Log::Che;
2 2     2   376673 use Mojo::Base 'Mojo::Log';
  2         161033  
  2         23  
3              
4 2     2   49109 use Carp 'croak';
  2         7  
  2         166  
5 2     2   19 use Fcntl ':flock';
  2         18  
  2         310  
6 2     2   18 use Mojo::File;
  2         6  
  2         4098  
7             #~ use Debug::LTrace qw/Mojo::Log::_log/;;
8             #~ use Carp::Trace;
9             #~ use Encode qw(decode_utf8);
10             #~ binmode STDERR, ":utf8";
11              
12             has paths => sub { {} };
13             has handlers => sub { {} };
14             has trace => 4;
15              
16             # Standard log levels
17             my %LEVEL = (debug => 1, info => 2, warn => 3, error => 4, fatal => 5);
18              
19             sub new {
20 6     6 1 40977 my $self = shift->SUPER::new(format => \&_format, @_);
21 6         251 $self->unsubscribe('message')->on(message => \&_message);
22 6         101 return $self;
23             }
24              
25             sub handler {
26 19     19 1 38 my ($self, $level) = @_;
27            
28 19         74 my $handler = $self->handlers->{$level};
29 19 50       85 return $handler
30             if $handler;
31            
32 19         58 my $path = shift->path;
33 19         96 my $path_level = $self->paths->{$level};
34 19 100       134 my $is_dir = -d -w $path
35             if $path;
36            
37 19         518 my $file;
38 19 100       71 if ($is_dir) {# DIR
    100          
39             # relative path for level
40 6 50       17 chop($path)
41             if $path =~ /\/$/;
42            
43 6   66     155 $file = sprintf "%s/%s", $path, $path_level ||"$level.log";
44             }
45             elsif ($path_level) {# absolute FILE for level
46 3         16 $file = $path_level;
47             }
48             else {
49             #~ croak "Cant create log handler for level=[$level] and path=[$path] (also check filesystem permissions)";
50 10         42 return; # Parent way to handle
51             }
52            
53 9 50       106 $handler = Mojo::File->new($file)->open('>>:encoding(UTF-8)')
54             or croak "Cant create log handler for [$file]";
55            
56 9         3133 $self->handlers->{$level} = $handler;
57            
58 9         71 return $handler;
59             };
60              
61             sub append {
62 19     19 1 54 my ($self, $msg, $handle) = @_;
63              
64 19 50 66     96 return unless $handle ||= $self->handle;
65 19         832 flock $handle, LOCK_EX;
66 19 50       96 $handle->print( $msg)
67             or croak "Can't write to log: $!";
68 19         1140 flock $handle, LOCK_UN;
69             }
70              
71             my @mon = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
72             my @wday = qw(Sn Mn Ts Wn Th Fr St);
73             sub _format {
74 19     19   117 my ($time, $level) = (shift, shift);
75 19 100 50     117 $level = '['.($LEVEL{$level} ? ($level =~ /^(\w)/)[0] : $level) . '] ' #"[$level] "
    100          
76             if $level //= '';
77            
78 19         508 my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($time);
79 19 100       267 $time = sprintf "%s %s %s %s:%s:%s", $wday[$wday], $mday, map(length == 1 ? "0$_" : $_, $mon[$mon], $hour, $min, $sec);
80            
81             #~ my $trace = '['. join(" ", @{_trace()}[1..2]) .']';
82            
83 19         159 return "$time $level" . join "\n", @_, '';
84             }
85              
86             sub _trace {
87 16   50 16   145 my $start = shift // 1;
88 16         185 my @call = caller($start);
89             return \@call
90 16 50       74 if @call;
91             #~ my @frames;
92 0         0 $start = 1;
93             #~ while (my @trace = caller($start++)) { push @call, \@trace }
94             #~ return pop @call;
95 0         0 while (@call = caller($start++)) { 1; }
  0         0  
96             #~ return $frames[4];
97 0         0 return \@call;
98             }
99              
100              
101             sub _message {
102 23     23   549 my ($self, $level) = (shift, shift);
103              
104 23 100 100     127 return unless !$LEVEL{$level} || $self->is_level($level);
105              
106 19         236 my $max = $self->max_history_size;
107 19         117 my $history = $self->history;
108 19         133 my $time = time;
109 19 100       49 my $trace = _trace($self->trace)
110             if $self->trace;
111 19 50 66     202 unshift @_, "$$〉". join(":", @$trace[$$trace[0] eq 'main' ? (1,2) : (0,2)]). ' ' . shift
    100          
112             if $trace && @$trace;
113 19         70 push @$history, my $msg = [$time, $level, @_];
114 19         54 shift @$history while @$history > $max;
115            
116 19 100       57 if (my $handle = $self->handler($level)) {
117 9         39 return $self->append($self->format->($time, '', @_), $handle);
118             }
119              
120             # as parent
121 10         53 return $self->append($self->format->(@$msg));
122            
123             }
124              
125             sub AUTOLOAD {
126 6     6   124 my $self = shift;
127              
128 6         59 my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
129 6 50 33     95 Carp::croak "Undefined log level(subroutine) &${package}::$method called"
130             unless Scalar::Util::blessed $self && $self->isa(__PACKAGE__);
131              
132 6         34 return $self->_log( $method => @_ );
133            
134             }
135              
136             our $VERSION = '0.07';
137              
138             =encoding utf8
139              
140             Доброго всем
141              
142             =head1 Mojo::Log::Che
143              
144             I<¡ ¡ ¡ ALL GLORY TO GLORIA ! ! !>
145              
146             =head1 VERSION
147              
148             0.07
149              
150             =head1 NAME
151              
152             Mojo::Log::Che - Little child of great parent Mojo::Log.
153              
154             =head1 SYNOPSIS
155              
156             Parent Mojo::Log behavior just works
157              
158             use Mojo::Log::Che;
159             my $log = Mojo::Log::Log->new(path => '/var/log/mojo.log', level => 'warn');
160             $log->debug(...);
161              
162             =head2 EXTENDED THINGS
163              
164             # Set "path" to folder + have default "paths" for levels (be sure that mkdir /var/log/mojo)
165             my $log = Mojo::Log::Log->new(path => '/var/log/mojo');
166             $log->warn(...);# log to /var/log/mojo/warn.log
167             $log->error(...); # log to /var/log/mojo/error.log
168             $log->foo(...);# log to /var/log/mojo/foo.log
169            
170             # set "path" to folder + set custom relative "paths" (be sure that mkdir /var/log/mojo)
171             my $log = Mojo::Log::Log->new(path => '/var/log/mojo', paths=>{debug=>'dbg.log', foo=>'myfoo.log'});
172             $log->debug(...); # log to /var/log/mojo/dbg.log
173             $log->warn(...);# log to /var/log/mojo/warn.log
174             $log->foo(...);# log to /var/log/mojo/myfoo.log
175            
176             # set "path" to file + have default "paths" for levels
177             # this is standard Mojo::Log behavior + custom level/method also
178             my $log = Mojo::Log::Log->new(path => '/var/log/mojo.log');
179             $log->debug(...); # log to /var/log/mojo.log
180             $log->warn(...);# log to /var/log/mojo.log
181             $log->foo(...);# log to /var/log/mojo.log
182            
183             # set "path" to file + set custom absolute "paths"
184             my $log = Mojo::Log::Log->new(path => '/var/log/mojo.log', paths => {error=>'/var/log/mojo.error.log'});
185             $log->debug(...); # log to /var/log/mojo.log
186             $log->foo(...);# log to /var/log/mojo.log
187             $log->error(...); # log to /var/log/mojo.error.log
188            
189             # Log to STDERR + set custom absolute "paths"
190             $log->path(undef); # none path
191             $log->level('info');
192             $log->paths->{'error'} = '/var/log/error.log'; # absolute file only for error level
193             $log->error(...); # log to /var/log/error.log
194             $log->info(...); # log to STDERR
195             $log->debug(...); # no log
196             $log->foo(...); # anyway log to STDERR
197            
198              
199             =head1 DESCRIPTION
200              
201             This B is a extended logger module for L projects.
202              
203             =head1 EVENTS
204              
205             B inherits all events from L and override following ones.
206              
207             =head2 message
208              
209             See also parent L. Extends parent module logics for switching handlers.
210              
211             =head1 ATTRIBUTES
212              
213             B inherits all attributes from L
214              
215             =head2 handlers
216              
217             Hashref of created file handlers for standard and custom levels. For standard parent L logic none handlers but L will be in the scene.
218              
219             $log->handlers->{'foo'} = IO::Handle->new();
220              
221             =head2 path
222              
223             See parent L. Can set to folder and file path.
224              
225             =head2 paths
226              
227             Hashref map level names to absolute or relative to L
228              
229             $log->path('/var/log'); # folder relative
230             $log->paths->{'error'} = 'err.log';
231             $log->error(...);# /var/log/err.log
232             $log->info(...); # log to filename as level name /var/log/info.log
233            
234             $log->path(undef); # none
235             $log->paths->{'error'} = '/var/log/error.log'; # absolute path only error level
236             $log->error(...); # log to /var/log/error.log
237             $log->info(...); # log to STDERR
238              
239             =head2 trace
240              
241             An trace level, defaults to C<4>, C<0> value will disable trace log. This value pass to C.
242              
243             =head1 METHODS
244              
245             B inherits all methods from L and implements the
246             following new ones.
247              
248             =head2 handler($level)
249              
250             Return undef when L undefined or L is file or has not defined L for $level. In this case L will return default handler.
251              
252             Return file handler overwise.
253              
254             =head1 AUTOLOAD
255              
256             Autoloads nonstandard/custom levels excepts already defined keywords of this and parent modules L, L, L:
257              
258             qw(message _message format _format handle handler handlers
259             history level max_history_size path paths append debug error fatal info
260             is_level new warn catch emit has_subscribers on once subscribers unsubscribe
261             has attr tap _monkey_patch import)
262              
263             and maybe anymore!
264              
265              
266             $log->foo('bar here');
267              
268             That custom levels log always without reducing log output outside of level.
269              
270             =head1 SEE ALSO
271              
272             L, L, L, L.
273              
274             =head1 AUTHOR
275              
276             Михаил Че (Mikhail Che), C<< >>
277              
278             =head1 BUGS / CONTRIBUTING
279              
280             Please report any bugs or feature requests at L. Pull requests also welcome.
281              
282             =head1 COPYRIGHT
283              
284             Copyright 2017 Mikhail Che.
285              
286             This library is free software; you can redistribute it and/or modify
287             it under the same terms as Perl itself.
288              
289             =cut