File Coverage

blib/lib/Class/Scaffold/Log.pm
Criterion Covered Total %
statement 51 72 70.8
branch 12 36 33.3
condition 2 15 13.3
subroutine 16 19 84.2
pod 8 8 100.0
total 89 150 59.3


line stmt bran cond sub pod time code
1 2     2   60 use 5.008;
  2         8  
  2         104  
2 2     2   14 use warnings;
  2         5  
  2         87  
3 2     2   25 use strict;
  2         6  
  2         130  
4              
5             package Class::Scaffold::Log;
6             BEGIN {
7 2     2   34 $Class::Scaffold::Log::VERSION = '1.102280';
8             }
9             # ABSTRACT: Logging utilities
10 2     2   13 use Carp;
  2         5  
  2         167  
11 2     2   2081 use IO::File;
  2         5430  
  2         407  
12 2     2   2133 use Time::HiRes 'gettimeofday';
  2         4270  
  2         12  
13 2     2   462 use parent 'Class::Scaffold::Base';
  2         6  
  2         20  
14             __PACKAGE__->mk_singleton(qw(instance))
15             ->mk_scalar_accessors(qw(filename max_level))
16             ->mk_boolean_accessors(qw(pid timestamp))->mk_concat_accessors(qw(output));
17 2     2   309 use constant DEFAULTS => (max_level => 1,);
  2         8  
  2         2401  
18              
19             sub init {
20 3     3 1 148 my $self = shift;
21 3         25 $self->SUPER::init(@_);
22 3         13 $self->clear_pid;
23 3         87 $self->set_timestamp;
24             }
25              
26             sub precdate {
27 3     3 1 19 my @hires = gettimeofday;
28             return sub {
29 3     3   35 sprintf "%04d%02d%02d.%02d%02d%02d",
30             $_[5] + 1900, $_[4] + 1, @_[ 3, 2, 1, 0 ];
31             }
32 3 50       194 ->(localtime($hires[0])) . (@_ ? sprintf(".%06d", $hires[1]) : "");
33             }
34 3     3 1 24 sub logdate { substr(precdate(1), 0, 18) }
35              
36             # like get_set_std, but also generate handle from filename unless defined
37             sub handle {
38 0     0 1 0 my $self = shift;
39 0 0       0 $self = Class::Scaffold::Log->instance unless ref $self;
40              
41             # in test mode, ignore what we're given - always log to STDOUT.
42 0 0       0 if ($self->delegate->test_mode) {
43 0 0 0     0 return $self->{handle} ||= IO::File->new(">&STDOUT")
44             or die "can't open STDOUT: $!\n";
45             }
46 0 0       0 if (@_) {
47 0         0 $self->{handle} = shift;
48             } else {
49 0 0       0 if ($self->filename) {
50 0 0 0     0 $self->{handle} ||= IO::File->new(sprintf(">>%s", $self->filename))
51             or die sprintf("can't append to %s: %s\n", $self->filename, $!);
52             } else {
53 0 0 0     0 $self->{handle} ||= IO::File->new(">&STDERR")
54             or die "can't open STDERR: $!\n";
55             }
56 0         0 $self->{handle}->autoflush(1);
57 0         0 return $self->{handle};
58             }
59             }
60              
61             # called like printf
62             sub __log {
63 6     6   16 my ($self, $level, $format, @args) = @_;
64 6 100       21 $self = Class::Scaffold::Log->instance unless ref $self;
65              
66             # Check for max_level before stringifying $format so we don't
67             # unnecessarily trigger a potentially lazy string.
68 6 100       23 return if $level > $self->max_level;
69              
70             # in case someone passes us an object that needs to be stringified so we
71             # can compare it with 'ne' further down (e.g., an exception object):
72 5         28 $format = "$format";
73 5 50 33     25 return unless defined $format and $format ne '';
74              
75             # make sure there's exactly one newline at the end
76 5         14 1 while chomp $format;
77 5         4 $format .= "\n";
78 5 100       14 $format = sprintf "(%08d) %s", $$, $format if $self->pid;
79 5 100       47 $format = sprintf "%s %s", $self->logdate, $format if $self->timestamp;
80 5         25 my $msg = sprintf $format => @args;
81              
82             # Open and close the file for each line that is logged. That doesn't cost
83             # much and makes it possible to move the file away for backup, rotation
84             # or whatver.
85 5         6 my $fh;
86 5 50 33     13 if ($self->delegate->test_mode) {
    50          
87 0         0 print $msg;
88             } elsif (defined($self->filename) && length($self->filename)) {
89 0 0       0 open $fh, '>>', $self->filename
90             or die sprintf "can't open %s for appending: %s", $self->filename, $!;
91 0 0       0 print $fh $msg
92             or die sprintf "can't print to %s: %s", $self->filename, $!;
93 0 0       0 close $fh
94             or die sprintf "can't close %s: %s", $self->filename, $!;
95             } else {
96 5         153 warn $msg;
97             }
98 5         17 $self->output($msg);
99             }
100              
101             sub info {
102 4     4 1 9 my $self = shift;
103 4         11 $self->__log(1, @_);
104             }
105              
106             sub debug {
107 2     2 1 3 my $self = shift;
108 2         5 $self->__log(2, @_);
109             }
110              
111             sub deep_debug {
112 0     0 1   my $self = shift;
113 0           $self->__log(3, @_);
114             }
115              
116             # log a final message, close the log and croak.
117             sub fatal {
118 0     0 1   my ($self, $format, @args) = @_;
119 0           my $message = sprintf($format, @args);
120 0           $self->info($message);
121 0           croak($message);
122             }
123             1;
124              
125              
126             __END__