File Coverage

blib/lib/Log/Tiny.pm
Criterion Covered Total %
statement 64 65 98.4
branch 14 22 63.6
condition 2 4 50.0
subroutine 12 12 100.0
pod 4 4 100.0
total 96 107 89.7


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