File Coverage

blib/lib/Log/Emitter.pm
Criterion Covered Total %
statement 52 53 98.1
branch 7 10 70.0
condition 4 9 44.4
subroutine 23 24 95.8
pod 11 12 91.6
total 97 108 89.8


line stmt bran cond sub pod time code
1             package Log::Emitter;
2              
3 2     2   156366 use Class::Method::Modifiers ();
  2         3238  
  2         44  
4 2     2   12 use Carp 'croak';
  2         4  
  2         105  
5 2     2   12 use Fcntl ':flock';
  2         4  
  2         269  
6 2     2   12 use Encode 'find_encoding';
  2         3  
  2         79  
7 2     2   11 use IO::Handle ();
  2         4  
  2         267  
8              
9             use Class::Tiny::Chained {
10 4         137 format => sub { \&_format },
11             handle => sub {
12              
13             # STDERR
14 4 100       113 return \*STDERR unless my $path = shift->path;
15              
16             # File
17 2 50       204 croak qq{Can't open log file "$path": $!} unless open my $file, '>>', $path;
18 2         48 return $file;
19             },
20 3         75 history => sub { [] },
21 2         45 level => 'debug',
22             max_history_size => 10,
23 2     2   1572 }, 'path';
  2         15903  
24              
25             Class::Method::Modifiers::before 'path' => sub { delete $_[0]{handle} if @_ > 1 };
26              
27 2     2   3749 use Role::Tiny::With;
  2         16408  
  2         1933  
28             with 'Role::EventEmitter';
29              
30             our $VERSION = '0.004';
31              
32             # Supported log levels
33             my $LEVEL = {debug => 1, info => 2, warn => 3, error => 4, fatal => 5};
34              
35             # Encoding cache
36             my $CACHE;
37              
38 5     5 0 5058 sub BUILD { shift->on(message => \&_message) }
39              
40             sub append {
41 9     9 1 18 my ($self, $msg) = @_;
42              
43 9 50       193 return unless my $handle = $self->handle;
44 9         171 flock $handle, LOCK_EX;
45 9 50       22 $handle->print(_encoding()->encode("$msg")) or croak "Can't write to log: $!";
46 9         566 flock $handle, LOCK_UN;
47             }
48              
49 4     4 1 66 sub debug { shift->_log(debug => @_) }
50 5     5 1 687 sub error { shift->_log(error => @_) }
51 4     4 1 610 sub fatal { shift->_log(fatal => @_) }
52 2     2 1 633 sub info { shift->_log(info => @_) }
53              
54 5     5 1 6753 sub is_debug { shift->_now('debug') }
55 5     5 1 1334 sub is_error { shift->_now('error') }
56             # For Log::Contextual compatiblity
57 0     0 1 0 sub is_fatal { 1 }
58 5     5 1 1323 sub is_info { shift->_now('info') }
59 5     5 1 1408 sub is_warn { shift->_now('warn') }
60              
61 1     1 1 552 sub warn { shift->_log(warn => @_) }
62              
63             sub _encoding {
64 9   33 9   74 $CACHE ||= find_encoding('UTF-8') || croak "Unknown encoding 'UTF-8'";
      66        
65             }
66              
67             sub _format {
68 12     12   465 '[' . localtime(shift) . '] [' . shift() . '] ' . join "\n", @_, '';
69             }
70              
71 16     16   47 sub _log { shift->emit('message', shift, @_) }
72              
73             sub _message {
74 11     11   91 my ($self, $level) = (shift, shift);
75              
76 11 100       24 return unless $self->_now($level);
77              
78 9         262 my $max = $self->max_history_size;
79 9         221 my $history = $self->history;
80 9         65 push @$history, my $msg = [time, $level, @_];
81 9         31 shift @$history while @$history > $max;
82              
83 9         180 $self->append($self->format->(@$msg));
84             }
85              
86 31   33 31   823 sub _now { $LEVEL->{pop()} >= $LEVEL->{$ENV{LOG_EMITTER_LEVEL} || shift->level} }
87              
88             1;
89              
90             =encoding utf8
91              
92             =head1 NAME
93              
94             Log::Emitter - Simple logger
95              
96             =head1 SYNOPSIS
97              
98             use Log::Emitter;
99              
100             # Log to STDERR
101             my $log = Log::Emitter->new;
102              
103             # Customize log file location and minimum log level
104             my $log = Log::Emitter->new(path => '/var/log/emitter.log', level => 'warn');
105              
106             # Log messages
107             $log->debug('Not sure what is happening here');
108             $log->info('FYI: it happened again');
109             $log->warn('This might be a problem');
110             $log->error('Garden variety error');
111             $log->fatal('Boom');
112              
113             =head1 DESCRIPTION
114              
115             L is a simple logger based on L.
116              
117             L is compatible with L for global logging.
118              
119             use Log::Emitter;
120             use Log::Contextual ':log', 'set_logger', -levels => [qw(debug info warn error fatal)];
121             set_logger(Log::Emitter->new);
122            
123             log_info { "Here's some info" };
124             log_error { "Uh-oh, error occured" };
125              
126             =head1 EVENTS
127              
128             L composes all events from L in addition to
129             emitting the following.
130              
131             =head2 message
132              
133             $log->on(message => sub {
134             my ($log, $level, @lines) = @_;
135             ...
136             });
137              
138             Emitted when a new message gets logged.
139              
140             $log->unsubscribe('message');
141             $log->on(message => sub {
142             my ($log, $level, @lines) = @_;
143             say "$level: ", @lines;
144             });
145              
146             =head1 ATTRIBUTES
147              
148             L implements the following attributes.
149              
150             =head2 format
151              
152             my $cb = $log->format;
153             $log = $log->format(sub {...});
154              
155             A callback for formatting log messages.
156              
157             $log->format(sub {
158             my ($time, $level, @lines) = @_;
159             return "[Thu May 15 17:47:04 2014] [info] I ♥ Logging\n";
160             });
161              
162             =head2 handle
163              
164             my $handle = $log->handle;
165             $log = $log->handle(IO::Handle->new);
166              
167             Log filehandle used by default L event, defaults to opening
168             L or C. Reset when L is set.
169              
170             =head2 history
171              
172             my $history = $log->history;
173             $log = $log->history([[time, 'debug', 'That went wrong']]);
174              
175             The last few logged messages.
176              
177             =head2 level
178              
179             my $level = $log->level;
180             $log = $log->level('debug');
181              
182             Active log level, defaults to C. Available log levels are C,
183             C, C, C and C, in that order. Note that the
184             C environment variable can override this value.
185              
186             =head2 max_history_size
187              
188             my $size = $log->max_history_size;
189             $log = $log->max_history_size(5);
190              
191             Maximum number of logged messages to store in L, defaults to C<10>.
192              
193             =head2 path
194              
195             my $path = $log->path
196             $log = $log->path('/var/log/emitter.log');
197              
198             Log file path used by L. Setting this attribute will reset
199             L.
200              
201             =head1 METHODS
202              
203             L composes all methods from L in addition to
204             the following.
205              
206             =head2 new
207              
208             my $log = Log::Emitter->new;
209              
210             Construct a new L object and subscribe to L event
211             with default logger.
212              
213             =head2 append
214              
215             $log->append("[Thu May 15 17:47:04 2014] [info] I ♥ Logging\n");
216              
217             Append message to L.
218              
219             =head2 debug
220              
221             $log = $log->debug('You screwed up, but that is ok');
222             $log = $log->debug('All', 'cool');
223              
224             Emit L event and log debug message.
225              
226             =head2 error
227              
228             $log = $log->error('You really screwed up this time');
229             $log = $log->error('Wow', 'seriously');
230              
231             Emit L event and log error message.
232              
233             =head2 fatal
234              
235             $log = $log->fatal('Its over...');
236             $log = $log->fatal('Bye', 'bye');
237              
238             Emit L event and log fatal message.
239              
240             =head2 info
241              
242             $log = $log->info('You are bad, but you prolly know already');
243             $log = $log->info('Ok', 'then');
244              
245             Emit L event and log info message.
246              
247             =head2 is_debug
248              
249             my $bool = $log->is_debug;
250              
251             Check for debug log level.
252              
253             =head2 is_error
254              
255             my $bool = $log->is_error;
256              
257             Check for error log level.
258              
259             =head2 is_fatal
260              
261             my $bool = $log->is_fatal;
262              
263             Always true.
264              
265             =head2 is_info
266              
267             my $bool = $log->is_info;
268              
269             Check for info log level.
270              
271             =head2 is_warn
272              
273             my $bool = $log->is_warn;
274              
275             Check for warn log level.
276              
277             =head2 warn
278              
279             $log = $log->warn('Dont do that Dave...');
280             $log = $log->warn('No', 'really');
281              
282             Emit L event and log warn message.
283              
284             =head1 BUGS
285              
286             Report any issues on the public bugtracker.
287              
288             =head1 AUTHOR
289              
290             Dan Book
291              
292             =head1 COPYRIGHT AND LICENSE
293              
294             This software is Copyright (c) 2015 by Dan Book.
295              
296             This is free software, licensed under:
297              
298             The Artistic License 2.0 (GPL Compatible)
299              
300             =head1 SEE ALSO
301              
302             L, L
303              
304             =for Pod::Coverage BUILD