File Coverage

blib/lib/Mojo/Log/Che.pm
Criterion Covered Total %
statement 62 66 93.9
branch 27 36 75.0
condition 11 19 57.8
subroutine 12 12 100.0
pod 3 3 100.0
total 115 136 84.5


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