File Coverage

blib/lib/Log/Tiny.pm
Criterion Covered Total %
statement 68 69 98.5
branch 14 22 63.6
condition 2 4 50.0
subroutine 12 12 100.0
pod 4 4 100.0
total 100 111 90.0


line stmt bran cond sub pod time code
1             package Log::Tiny;
2              
3 4     4   87637 use strict;
  4         8  
  4         124  
4 4     4   20 use vars qw($AUTOLOAD $VERSION $errstr %formats);
  4         7  
  4         5321  
5              
6             =head1 NAME
7              
8             Log::Tiny - Log data with as little code as possible
9              
10             =head1 VERSION
11              
12             Version 1.0
13              
14             =cut
15              
16             $VERSION = '1.0';
17             $errstr = '';
18              
19             %formats = (
20             c => [ 's', sub { shift }, ], # category: AUTOLOAD
21             C => [ 's', sub { lc shift }, ], # lcategory: AUTOLOAD lc
22             f => [ 's', sub { $0 }, ], # program_file: $0
23             F => [ 's', sub { (caller(2))[1] }, ], # caller_file: caller
24             g => [ 's', sub { scalar gmtime }, ], # gmtime: scalar gmtime
25             L => [ 'd', sub { (caller(2))[2] }, ], # caller_line: caller
26             m => [ 's', sub { shift; shift }, ], # message: args
27             n => [ 's', sub { $/ }, ], # newline: $/
28             o => [ 's', sub { $^O }, ], # osname: $^O
29             p => [ 'd', sub { $$ }, ], # pid: $$
30             P => [ 's', sub { (caller(2))[0] }, ], # caller_pkg: caller
31             r => [ 'd', sub { time - $^T }, ], # runtime: $^T
32             S => [ 's', \&__format_S, sub { my $t = (caller(2))[3]; }, ], # caller_sub: caller
33             t => [ 's', sub { scalar localtime }, ],# localtime: scalar localtime
34             T => [ 'd', sub { time }, ], # unix_time: time
35             u => [ 'd', sub { $> }, ], # effective_uid: $>
36             U => [ 'd', sub { $< }, ], # real_uid: $<
37             v => [ 'd', sub { $] }, ], # long_perl_ver: $]
38             V => [ 's', sub { sprintf("%vd", $^V) }, ], # short_perl_ver
39             );
40              
41 1 50   1   7 sub __format_S { my $t = (caller(2))[3]; if ( $t eq 'Log::Tiny::AUTOLOAD' ) { $t = 'main'; }; $t; }
  1         4  
  1         3  
  1         3  
42              
43             =head1 SYNOPSIS
44              
45             This module aims to be a light-weight implementation
46             *similiar* to L for logging data to a file.
47              
48             Its use is very straight forward:
49              
50             use Log::Tiny;
51              
52             my $log = Log::Tiny->new( 'myapp.log' ) or
53             die 'Could not log! (' . Log::Tiny->errstr . ')';
54              
55             foreach ( 1 .. 20 ) {
56             $log->DEBUG( "Performing extensive computations on $_" ) if $DEBUG;
57             unless ( extensively_compute( $_ ) ) {
58             $log->WARN(
59             "Investigating error (this may take a while)..."
60             );
61             $log->ERROR( find_error() );
62             save_state();
63             exit 1;
64             } else {
65             $log->INFO( "Everything's A-OK!" );
66             }
67             }
68              
69             =head1 FUNCTIONS
70              
71             =head2 new
72              
73             Create a new Log::Tiny object. You must define a log file
74             to append to, and, optionally, a format.
75              
76             =cut
77              
78             sub new {
79 3     3 1 135 my $pkg = shift;
80 3   50     13 my $logfile = shift || return _error('No logfile provided');
81 3   50     12 my $format = shift || '[%t] %f:%p (%c) %m%n';
82 3 50       332 open (my $logfh, '>>' . $logfile ) ||
83             return _error( "Could not open $logfile: $!" );
84 3         25 my $self = bless {
85             format => $format,
86             methods_only => [],
87             logfile => $logfile,
88             logfh => $logfh,
89             }, $pkg;
90 3         20 $self->format();
91 3         11 return $self;
92             }
93              
94             =head2 format
95              
96             You may, at any time, change the format. The log format is
97             similiar in style to the sprintf you know and love; and, as
98             a peek inside the source of this module will tell you, sprintf
99             is used internally. However, be advised that these log formats
100             B.
101              
102             Interpolated data are specified by an percent sign (C< % >),
103             followed by a character. A literal percent sign can be
104             specified via two in succession ( C< %% > ). You may use any
105             of the formatting attributes as noted in L, under
106             "sprintf" (C).
107              
108             Internally, the format routine uses a data structure (hash)
109             that can be seen near the beggining of this package. Any
110             unrecognized interpolation variables will be returned
111             literally. This means that, assuming $format{d} does not
112             exist, "%d" in your format will result in "%d" being outputted
113             to the log file. No interpolation will occur.
114              
115             You may, of course, decide to modify the format data structure.
116             I have done my best to ensure a wide range of variables for your
117             usage, however. They are (currently) as follows:
118              
119             c => category => The method called (see below for more info)
120             C => lcategory => lowercase category
121             f => program_file => Value of $0
122             F => caller_file => Calling file
123             g => gmtime => Output of scalar L (localized date string)
124             L => caller_line => Calling line
125             m => message => Message sent to the log method
126             n => newline => Value of $/
127             o => osname => Value of $^O
128             p => pid => Value of $$
129             P => caller_pkg => Calling package
130             r => runtime => Seconds the current process has been running for
131             S => caller_sub => Calling subroutine
132             t => localtime => Output of scalar L (localized date
133             string)
134             T => unix_time => Time since epoch (L
135             u => effective_uid => Value of $>
136             U => real_uid => Value of $<
137             v => long_perl_ver => Value of $] (5.008008)
138             V => short_perl_ver => A "short" string for the version ("5.8.8")
139              
140             See L for information on the used global variables, and
141             L (under "caller") or C for information
142             on the "calling" variables. Oh, and make sure you add %n if you want
143             newines.
144              
145             =cut
146              
147             sub format {
148 3     3 1 6 my $self = shift;
149 3 50       13 if ( $_[0] ) {
150 0         0 $self->{format} = shift;
151             }
152 3         20 $self->{args} = [];
153             # make real format
154 3         28 my $format = join '', keys %formats;
155             $self->{format} =~
156 3         137 s/%(-?\d*(?:\.\d+)?)([$format])/_replace($self, $1, $2);/gex;
  6         23  
157             # thanks, mschilli
158 3         10 return $self->{format};
159             }
160              
161             sub _replace {
162 6     6   19 my ( $self, $num, $op ) = @_;
163 6 50       21 return '%%' if $op eq '%';
164 6 50       20 return "%%$op" unless defined $formats{$op};
165 6         8 push @{ $self->{args} }, $op;
  6         20  
166 6         37 return "%$num" . $formats{$op}->[ 0 ];
167             }
168              
169             =head2 WHATEVER_YOU_WANT (log a message)
170              
171             This method is whatever you want it to be. Any method called
172             on a Log::Tiny object that is not reserved will be considered
173             an attempt to log in the category named the same as the method
174             that was caleld. Currently, only in-use methods are reserved;
175             However, to account for expansion, please only use uppercase
176             categories. See formats above for information on customizing
177             the log messages.
178              
179             =cut
180              
181             sub AUTOLOAD {
182 17     17   570 my $self = shift;
183 17         29 my $method = $AUTOLOAD;
184 17         63 $method =~ s/.*:://;
185 17 50       55 return _error( "Log routine ($method) is not a class method" )
186             unless defined ref $self;
187 17 100       21 if (@{ $self->{methods_only} }) {
  17         57  
188 3         4 my $in = 0;
189 3         6 foreach (@{ $self->{methods_only} }) {
  3         7  
190 6 100       21 $in++ if uc $method eq uc $_;
191             }
192 3 100       12 return _error( "Log category '$method' not in whitelist" )
193             unless $in;
194             }
195 16         28 my $tmp = '';
196             $tmp .= sprintf (
197             $self->{format},
198             $self->_mk_args( $method, $_ ),
199 16         62 ) foreach @_;
200 16         20 my $ret;
201             {
202 16         24 my $autoflush = $|++;
  16         41  
203 16         22 $ret = print {$self->{logfh}} $tmp;
  16         56  
204 16         67 $| = $autoflush;
205             }
206 16         43 return $ret;
207             }
208              
209             sub _mk_args {
210 16     16   20 my $self = shift;
211 16         35 my ( $method, $msg ) = @_;
212 16 50       41 $msg = '' unless defined $msg;
213 16         23 my @ret = @{ $self->{args} };
  16         49  
214 16         29 my %need = map { $_ => undef } @ret;
  30         83  
215 16         47 foreach ( keys %need ) {
216 30         72 $need{ $_ } = $formats{ $_ }->[ 1 ]->( $method, $msg );
217             }
218 16         64 s/^(\w)$/$need{$1}/e foreach @ret;
  30         130  
219 16         111 return @ret;
220             }
221              
222 3 50   3   205 sub DESTROY { close shift->{logfh} or warn "Couldn't close log file: $!"; }
223              
224             =head2 errstr
225              
226             Called as a class method, C< Log::Tiny->errstr > reveals the
227             error that Log::Tiny encountered in creation or invocation.
228              
229             =cut
230              
231 2     2 1 985 sub errstr { $errstr; }
232 1     1   2 sub _error { $errstr = shift; undef; }
  1         4  
233              
234             =head2 log_only
235              
236             Log only the given categories
237              
238             =cut
239              
240             sub log_only {
241 1     1 1 3 my $self = shift;
242 1         3 $self->{methods_only} = \@_;
243             }
244              
245             =head1 AUTHOR
246              
247             Jordan M. Adler, C<< >>
248              
249             =head1 BUGS
250              
251             Please report any bugs or feature requests to
252             C, or through the web interface at
253             L.
254             I will be notified, and then you'll automatically be notified of progress on
255             your bug as I make changes.
256              
257             =head1 SUPPORT
258              
259             You can find documentation for this module with the perldoc command.
260              
261             perldoc Log::Tiny
262              
263             You can also look for information at:
264              
265             =over 4
266              
267             =item * AnnoCPAN: Annotated CPAN documentation
268              
269             L
270              
271             =item * CPAN Ratings
272              
273             L
274              
275             =item * RT: CPAN's request tracker
276              
277             L
278              
279             =item * Search CPAN
280              
281             L
282              
283             =item * GitHub
284              
285             L
286              
287             =back
288              
289             =head1 ACKNOWLEDGEMENTS
290              
291             Much thanks to Michael Schilli C for his great work on
292             Log::Log4perl, of which this module's formatting concept is largely based upon.
293              
294             =head1 COPYRIGHT & LICENSE
295              
296             Copyright 2007-2015 Jordan M. Adler, all rights reserved.
297              
298             This program is free software; you can redistribute it and/or modify it
299             under the same terms as Perl itself.
300              
301             =cut
302              
303             1; # End of Log::Tiny