File Coverage

blib/lib/Mojo/Log/Che.pm
Criterion Covered Total %
statement 69 73 94.5
branch 30 40 75.0
condition 12 22 54.5
subroutine 13 13 100.0
pod 4 4 100.0
total 128 152 84.2


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