File Coverage

blib/lib/Basset/Logger.pm
Criterion Covered Total %
statement 49 49 100.0
branch 28 30 93.3
condition 2 2 100.0
subroutine 9 9 100.0
pod 2 3 66.6
total 90 93 96.7


line stmt bran cond sub pod time code
1             package Basset::Logger;
2              
3             #Basset::Logger, copyright and (c) 2004, 2006 James A Thomason III
4             #Basset::Logger is distributed under the terms of the Perl Artistic License.
5              
6             =pod
7              
8             =head1 NAME
9              
10             Basset::Logger - Logger object. Writes things to files.
11              
12             =head1 AUTHOR
13              
14             Jim Thomason, jim@jimandkoka.com
15              
16             =head1 DESCRIPTION
17              
18             my $logger = Basset::Logger->new(
19             'handle' => '/tmp/weasels.log'
20             );
21              
22             $logger->log("Weasels in the hen house!");
23              
24             $logger->close();
25              
26             Create a logger object, then log data to it, then close it when you're done. Easy as pie.
27             Works beautifully in conjunction with Basset::NotificationCenter.
28              
29             You will B to put a types entry into your conf file for
30              
31             logger=Basset::Logger
32              
33             (or whatever center you're using)
34              
35             =cut
36              
37              
38             $VERSION = '1.01';
39              
40 2     2   28746 use Basset::Object;
  2         8  
  2         135  
41             our @ISA = Basset::Object->pkg_for_type('object');
42              
43 2     2   16 use strict;
  2         4  
  2         75  
44 2     2   12 use warnings;
  2         4  
  2         1781  
45              
46             =pod
47              
48             =head1 ATTRIBUTES
49              
50             =over
51              
52             =item handle
53              
54             The place you log to. Either a string (which will be opened in append mode) or a globref.
55              
56             $logger->handle('/path/to/log.log');
57             open (LOG, ">>/path/to/log.log");
58             $logger->handle(\*LOG);
59              
60             =cut
61              
62             __PACKAGE__->add_attr(['handle', '_isa_file_accessor']);
63              
64             =pod
65              
66             =begin btest handle
67              
68             my $o = __PACKAGE__->new();
69             $test->ok($o, "Got object for handle");
70             $test->is(scalar($o->handle($o)), undef, "Cannot set handle to unknown reference");
71             $test->is($o->errcode, "BL-03", "proper error code");
72              
73             local $@ = undef;
74             eval "use File::Temp";
75             my $file_temp_exists = $@ ? 0 : 1;
76              
77             if ($file_temp_exists) {
78             my $temp = File::Temp->new;
79             my $name = $temp->filename;
80             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
81             open (my $glob, $name);
82             $test->is($o->handle($glob), $glob, "set glob");
83             chmod 000, $name;
84             $test->is(scalar($o->handle($name)), undef, "could not set handle to unwritable file");
85             $test->is($o->errcode, "BL-01", "proper error code");
86             }
87              
88             =end btest
89              
90             =cut
91              
92              
93             =pod
94              
95             =item closed
96              
97             =cut
98              
99             __PACKAGE__->add_attr('closed');
100              
101             =pod
102              
103             =begin btest closed
104              
105             {
106             my $o = __PACKAGE__->new();
107             $test->ok($o, "Got object");
108             $test->is(scalar(__PACKAGE__->closed), undef, "could not call object method as class method");
109             $test->is(__PACKAGE__->errcode, "BO-08", "proper error code");
110             $test->is(scalar($o->closed), 0, 'closed is 0 by default');
111             $test->is($o->closed('abc'), 'abc', 'set closed to abc');
112             $test->is($o->closed(), 'abc', 'read value of closed - abc');
113             my $h = {};
114             $test->ok($h, 'got hashref');
115             $test->is($o->closed($h), $h, 'set closed to hashref');
116             $test->is($o->closed(), $h, 'read value of closed - hashref');
117             my $a = [];
118             $test->ok($a, 'got arrayref');
119             $test->is($o->closed($a), $a, 'set closed to arrayref');
120             $test->is($o->closed(), $a, 'read value of closed - arrayref');
121             }
122              
123             my $o = __PACKAGE__->new();
124             $test->ok($o, "got object");
125             $test->is($o->close, 1, "closing non-existent handle is fine");
126             $test->is($o->closed, 0, "handle remains open");
127              
128             local $@ = undef;
129             eval "use File::Temp";
130             my $file_temp_exists = $@ ? 0 : 1;
131              
132             if ($file_temp_exists) {
133             my $temp = File::Temp->new;
134             my $name = $temp->filename;
135             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
136             $test->is($o->closed, 0, "file handle is open");
137             $test->is($o->close, 1, "closed file handle");
138             $test->is($o->closed, 1, "filehandle is closed");
139             }
140              
141             =end btest
142              
143             =cut
144              
145              
146             =pod
147              
148             =item stamped
149              
150             =cut
151              
152             __PACKAGE__->add_attr('stamped');
153              
154             =pod
155              
156             =begin btest stamped
157              
158             my $o = __PACKAGE__->new();
159             $test->ok($o, "Got object");
160             $test->is(scalar(__PACKAGE__->stamped), undef, "could not call object method as class method");
161             $test->is(__PACKAGE__->errcode, "BO-08", "proper error code");
162             $test->is(scalar($o->stamped), 1, 'stamped is 1 by default');
163             $test->is($o->stamped('abc'), 'abc', 'set stamped to abc');
164             $test->is($o->stamped(), 'abc', 'read value of stamped - abc');
165             my $h = {};
166             $test->ok($h, 'got hashref');
167             $test->is($o->stamped($h), $h, 'set stamped to hashref');
168             $test->is($o->stamped(), $h, 'read value of stamped - hashref');
169             my $a = [];
170             $test->ok($a, 'got arrayref');
171             $test->is($o->stamped($a), $a, 'set stamped to arrayref');
172             $test->is($o->stamped(), $a, 'read value of stamped - arrayref');
173              
174             =end btest
175              
176             =cut
177              
178              
179             sub init {
180             return shift->SUPER::init(
181 7     7 1 40 'closed' => 0,
182             'stamped' => 1,
183             @_
184             );
185             };
186              
187             =pod
188              
189             =begin btest init
190              
191             my $o = __PACKAGE__->new();
192             $test->ok($o, "Got logger object");
193             $test->is($o->closed, 0, 'closed is 0');
194             $test->is($o->stamped, 1, 'stamped is 1');
195              
196             =end btest
197              
198             =cut
199              
200              
201             # _file_accessor is a dumbed down version of the one in Mail::Bulkmail.
202             #
203             # _file_accessor is an internal accessor for accessing external information. Said external information can be a
204             # path to a file or a globref containing an already openned file handle. It will open up path/to/file strings and
205             # create an internal filehandle. it also makes sure that all filehandles are piping hot.
206              
207             sub _isa_file_accessor {
208 2     2   5 my $pkg = shift;
209 2         4 my $attr = shift;
210 2         4 my $prop = shift;
211            
212             return sub {
213 32     32   696854 my $self = shift;
214 32         47 my $file = shift;
215            
216 32 100       77 if (defined $file){
217 14 100       42 if (! ref $file) {
    100          
218 12         72 my $handle = $self->gen_handle();
219 12 50       639 open ($handle, ">>" . $file)
220             or return $self->error("Could not open file $file : $!", "BL-01");
221 12         96 select((select($handle), $| = 1)[0]); #Make sure the file is piping hot!
222 12         64 $self->closed(0);
223 12         65 return $self->$prop($handle);
224             }
225             elsif (ref ($file) eq 'GLOB') {
226 1         6 select((select($file), $| = 1)[0]); #Make sure the file is piping hot!
227 1         4 $self->closed(0);
228 1         4 return $self->$prop($file);
229             }
230             else {
231 1         12 return $self->error("File error. I don't know what a $file is", "BL-03");
232             };
233             }
234             else {
235 18         77 return $self->$prop();
236             };
237             }
238              
239 2         10 };
240              
241             =pod
242              
243             =item log
244              
245             logs the item to the logger's handle.
246              
247             $logger->log("one val", "two vals", "three vals");
248              
249             prints out one per line, tab indented on subsequent lines.
250              
251             one val
252             two vals
253             three vals
254              
255             =cut
256              
257             sub log {
258 11     11 1 29 my $self = shift;
259 11 100       62 my $note = shift or return $self->error("Cannot log w/o notification", "BL-07");
260            
261 10 100       44 return $self->error("Cannot log to closed handle", "BL-08") if $self->closed;
262            
263 9 100 100     58 my $args = ref $note ? $note->{'args'} || [] : [$note];
264              
265 9 100       35 my $handle = $self->handle or return;
266              
267 8         18 my $printed = 0;
268            
269 8 100       29 if (@$args) {
270            
271 7 100       30 if ($self->stamped) {
272 4         436 my $stamp = localtime;
273 4         247 print $handle "AT (", $stamp, "):\t";
274             };
275            
276 7         24 foreach my $value (@$args) {
277 10 100       34 my $tab = $printed++ ? "\t" : "";
278 10 100       541 print $handle $tab, $value, "\n" if defined $value;
279             };
280             }
281            
282 8         57 return 1;
283              
284             };
285              
286             =pod
287              
288             =begin btest log
289              
290             my $o = __PACKAGE__->new();
291             $test->ok($o, "got object");
292             $test->is($o->close, 1, "closing non-existent handle is fine");
293             $test->is($o->closed, 0, "handle remains open");
294              
295             $test->is(scalar($o->log('foo')), undef, "Cannot log w/o handle");
296              
297             $test->is($o->closed(1), 1, "closed handle");
298             $test->is(scalar($o->log), undef, "Cannot log w/o note");
299             $test->is($o->errcode, "BL-07", "proper error code");
300             $test->is(scalar($o->log('foo')), undef, "Cannot log to closed handle");
301             $test->is($o->errcode, "BL-08", "proper error code");
302              
303              
304             local $@ = undef;
305             eval "use File::Temp";
306             my $file_temp_exists = $@ ? 0 : 1;
307              
308             if ($file_temp_exists) {
309             {
310             my $temp = File::Temp->new;
311             my $name = $temp->filename;
312             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
313             $test->is($o->log('foo'), 1, "logged foo to file");
314             open (my $reader, $name);
315             {
316             local $/ = undef;
317             my $in_file = <$reader>;
318             $test->like($in_file, qr{^AT \(\w+\s+\w+\s+\d+\s+\d+:\d+:\d+\s+\d+\):\tfoo\n$}, "data was logged to file with stamp");
319             }
320             }
321             {
322             $test->is($o->stamped(0), 0, "shut off time stamping");
323             my $temp = File::Temp->new;
324             my $name = $temp->filename;
325             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
326             $test->is($o->log('foo'), 1, "logged foo to file");
327             open (my $reader, $name);
328             {
329             local $/ = undef;
330             my $in_file = <$reader>;
331             $test->like($in_file, qr{^foo\n$}, "data was logged to file without stamp");
332             }
333             $test->is($o->stamped(1), 1, "turned on time stamping");
334             }
335             {
336             my $temp = File::Temp->new;
337             my $name = $temp->filename;
338             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
339             $test->is($o->log({'args' => ['foo']}), 1, "logged foo to file in note");
340             open (my $reader, $name);
341             {
342             local $/ = undef;
343             my $in_file = <$reader>;
344             $test->like($in_file, qr{^AT \(\w+\s+\w+\s+\d+\s+\d+:\d+:\d+\s+\d+\):\tfoo\n$}, "data was logged to file with stamp");
345             }
346             }
347             {
348             $test->is($o->stamped(0), 0, "shut off time stamping");
349             my $temp = File::Temp->new;
350             my $name = $temp->filename;
351             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
352             $test->is($o->log({'args' => ['foo']}), 1, "logged foo to file in note");
353             open (my $reader, $name);
354             {
355             local $/ = undef;
356             my $in_file = <$reader>;
357             $test->like($in_file, qr{^foo\n$}, "data was logged to file without stamp");
358             }
359             $test->is($o->stamped(1), 1, "turned on time stamping");
360             }
361             {
362             my $temp = File::Temp->new;
363             my $name = $temp->filename;
364             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
365             $test->is($o->log({'args' => ['foo', 'bar']}), 1, "logged foo, bar to file in note");
366             open (my $reader, $name);
367             {
368             local $/ = undef;
369             my $in_file = <$reader>;
370             $test->like($in_file, qr{^AT \(\w+\s+\w+\s+\d+\s+\d+:\d+:\d+\s+\d+\):\tfoo\n\tbar\n$}, "data was logged to file with stamp");
371             }
372             }
373             {
374             $test->is($o->stamped(0), 0, "shut off time stamping");
375             my $temp = File::Temp->new;
376             my $name = $temp->filename;
377             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
378             $test->is($o->log({'args' => ['foo', 'bar']}), 1, "logged foo, bar to file in note");
379             open (my $reader, $name);
380             {
381             local $/ = undef;
382             my $in_file = <$reader>;
383             $test->like($in_file, qr{^foo\n\tbar\n$}, "data was logged to file with stamp");
384             }
385             $test->is($o->stamped(1), 1, "turned on time stamping");
386             }
387             {
388             my $temp = File::Temp->new;
389             my $name = $temp->filename;
390             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
391             $test->is($o->log({'args' => ['foo', undef]}), 1, "logged foo, undef to file in note");
392             open (my $reader, $name);
393             {
394             local $/ = undef;
395             my $in_file = <$reader>;
396             $test->like($in_file, qr{^AT \(\w+\s+\w+\s+\d+\s+\d+:\d+:\d+\s+\d+\):\tfoo\n$}, "data was logged to file with stamp");
397             }
398             }
399             {
400             my $temp = File::Temp->new;
401             my $name = $temp->filename;
402             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
403             $test->is($o->log({}), 1, "logged empty note to file in note");
404             open (my $reader, $name);
405             {
406             local $/ = undef;
407             my $in_file = <$reader>;
408             $test->is($in_file,'', "no data logged w/o args");
409             }
410             }
411             }
412              
413              
414             =end btest
415              
416             =cut
417              
418              
419              
420             sub close {
421 9     9 0 1640 my $self = shift;
422              
423 9 100       27 my $handle = $self->handle or return 1;
424            
425 4 50       2261 close($handle) or return $self->error("Canot close handle : $!", "BL-06");
426            
427 4         25 $self->closed(1);
428            
429 4         1106 return 1;
430             }
431              
432             =pod
433              
434             =begin btest close
435              
436             my $o = __PACKAGE__->new();
437             $test->ok($o, "got object");
438             $test->is($o->close, 1, "closing non-existent handle is fine");
439             $test->is($o->closed, 0, "handle remains open");
440              
441             local $@ = undef;
442             eval "use File::Temp";
443             my $file_temp_exists = $@ ? 0 : 1;
444              
445             if ($file_temp_exists) {
446             my $temp = File::Temp->new;
447             my $name = $temp->filename;
448             $test->is(ref($o->handle($name)), 'GLOB', "created glob");
449             $test->is($o->closed, 0, "file handle is open");
450             $test->is($o->close, 1, "closed file handle");
451             $test->is($o->closed, 1, "filehandle is closed");
452             }
453              
454             =end btest
455              
456             =cut
457              
458              
459             sub DESTROY {
460 7     7   7220 my $self = shift;
461            
462 7 100       31 $self->close unless $self->closed;
463            
464             #$self->SUPER::DESTROY(@_);
465             }
466              
467             1;