File Coverage

blib/lib/CGI/Application/Plugin/LogDispatch.pm
Criterion Covered Total %
statement 126 152 82.8
branch 50 72 69.4
condition 9 19 47.3
subroutine 21 23 91.3
pod 2 2 100.0
total 208 268 77.6


)
line stmt bran cond sub pod time code
1             package CGI::Application::Plugin::LogDispatch;
2              
3 6     6   501667 use strict;
  6         16  
  6         289  
4 6     6   37 use vars qw($VERSION @EXPORT);
  6         10  
  6         387  
5              
6 6     6   6262 use Log::Dispatch;
  6         209872  
  6         296  
7 6     6   16192 use Log::Dispatch::Screen;
  6         49292  
  6         188  
8 6     6   61 use Scalar::Util ();
  6         353  
  6         112  
9 6     6   5379 use CGI::Application ();
  6         43687  
  6         125  
10 6     6   51 use File::Spec ();
  6         13  
  6         647  
11             require UNIVERSAL::require;
12              
13             $VERSION = '1.02';
14              
15             @EXPORT = qw(
16             log
17             log_config
18             );
19              
20             sub import {
21 9     9   19654 my $pkg = shift;
22 9         30 my $callpkg = caller;
23 6     6   35 no strict 'refs';
  6         12  
  6         6828  
24 9         30 foreach my $sym (@EXPORT) {
25 18         35 *{"${callpkg}::$sym"} = \&{$sym};
  18         138  
  18         55  
26             }
27 9 100       226 $callpkg->log_config(@_) if @_;
28             }
29              
30             sub log {
31 18     18 1 172183 my $self = shift;
32              
33 18         71 my ($log, $options, $frompkg) = _get_object_or_options($self);
34              
35 18 100       69 if (!$log) {
36             # define the config hash if it doesn't exist to save some checks later
37 7 50       33 $options = {} unless $options;
38              
39             # create Log::Dispatch object
40 7 100       36 if ($options->{LOG_DISPATCH_OPTIONS}) {
41             # use the parameters the user supplied
42 2         6 $log = Log::Dispatch->new( %{ $options->{LOG_DISPATCH_OPTIONS} } );
  2         27  
43             } else {
44 5         131 $log = Log::Dispatch->new( );
45             }
46              
47 7 50       854 if ($options->{LOG_DISPATCH_MODULES}) {
48 7         15 foreach my $logger (@{ $options->{LOG_DISPATCH_MODULES} }) {
  7         22  
49 9 50       554 if (!$logger->{module}) {
    50          
50             # no logger module provided
51             # not fatal... just skip this logger
52 0         0 warn "No 'module' name provided -- skipping this logger";
53             } elsif (!$logger->{module}->require) {
54             # Couldn't load the logger module
55             # not fatal... just skip this logger
56 0         0 warn $UNIVERSAL::require::ERROR;
57             } else {
58 9         3694 my $module = delete $logger->{module};
59             # setup a callback to append a newline if requested
60 9 100 66     329 if ($logger->{append_newline} || $options->{APPEND_NEWLINE}) {
61 2 50       18 delete $logger->{append_newline} if exists $logger->{append_newline};
62 2 50 33     13 $logger->{callbacks} = [ $logger->{callbacks} ]
63             if $logger->{callbacks} && ref $logger->{callbacks} ne 'ARRAY';
64 2         5 push @{ $logger->{callbacks} }, \&_append_newline;
  2         9  
65             }
66             # add the logger to the dispatcher
67 9         58 $log->add( $module->new( %$logger ) );
68             }
69             }
70             } else {
71             # create a simple STDERR logger
72 0         0 my %options = (
73             name => 'screen',
74             stderr => 1,
75             min_level => 'debug',
76             );
77 0 0       0 $options{callbacks} = \&_append_newline if $options->{APPEND_NEWLINE};
78 0         0 $log->add( Log::Dispatch::Screen->new( %options ) );
79             }
80 7   66     1786 _set_object($frompkg||$self, $log);
81              
82             # CAP::DevPopup support
83 7 50       83 if (UNIVERSAL::can($self, 'devpopup')) {
84             # Register our report with DevPopup
85 0         0 $self->add_callback( 'devpopup_report', \&_devpopup_report );
86              
87             # Create logger to capture all log entries
88             my %options = (
89             'name' => 'DevPopup',
90             'min_level' => 'debug',
91             'filename' => File::Spec->devnull(),
92             'callbacks' => sub {
93 0     0   0 my %args = @_;
94 0         0 push( @{$self->{LOG_DISPATCH_DEVPOPUP_HISTORY}}, [$args{level}, $args{message}] );
  0         0  
95             },
96 0         0 );
97 0         0 $log->add( Log::Dispatch::File->new(%options) );
98             }
99             }
100              
101 18         116 return $log;
102             }
103              
104             sub log_config {
105 7     7 1 60498 my $self = shift;
106 7 100       40 my $class = ref $self ? ref $self : $self;
107              
108 7         15 my $log_config;
109 7 100       25 if (ref $self) {
110 5 50 33     66 die "Calling log_config after the log object has already been created" if @_ && defined $self->{__LOG_OBJECT};
111 5   50     46 $log_config = $self->{__LOG_CONFIG} ||= {};
112             } else {
113 6     6   41 no strict 'refs';
  6         14  
  6         3739  
114 2 50 33     9 die "Calling log_config after the log object has already been created" if @_ && defined ${$class.'::__LOG_OBJECT'};
  2         21  
115 2   50     3 ${$class.'::__LOG_CONFIG'} ||= {};
  2         19  
116 2         3 $log_config = ${$class.'::__LOG_CONFIG'};
  2         8  
117             }
118              
119 7 50       290 if (@_) {
120 7         15 my $props;
121 7 50       32 if (ref($_[0]) eq 'HASH') {
122 0         0 my $rthash = %{$_[0]};
  0         0  
123 0         0 $props = CGI::Application->_cap_hash($_[0]);
124             } else {
125 7         58 $props = CGI::Application->_cap_hash({ @_ });
126             }
127 7         136 my %options;
128             # Check for LOG_OPTIONS
129 7 100       165 if ($props->{LOG_DISPATCH_OPTIONS}) {
130 2 50       13 die "log_config error: parameter LOG_DISPATCH_OPTIONS is not a hash reference"
131             if ref $props->{LOG_DISPATCH_OPTIONS} ne 'HASH';
132 2         8 $log_config->{LOG_DISPATCH_OPTIONS} = delete $props->{LOG_DISPATCH_OPTIONS};
133             }
134              
135             # Check for LOG_DISPATCH_MODULES
136 7 50       33 if ($props->{LOG_DISPATCH_MODULES}) {
137 7 50       36 die "log_config error: parameter LOG_DISPATCH_MODULES is not an array reference"
138             if ref $props->{LOG_DISPATCH_MODULES} ne 'ARRAY';
139 7         35 $log_config->{LOG_DISPATCH_MODULES} = delete $props->{LOG_DISPATCH_MODULES};
140             }
141              
142             # Check for APPEND_NEWLINE
143 7 50       29 if ($props->{APPEND_NEWLINE}) {
144 0         0 $log_config->{APPEND_NEWLINE} = 1;
145 0         0 delete $props->{APPEND_NEWLINE};
146             }
147              
148             # Check for LOG_METHOD_EXECUTION
149 7 100       36 if ($props->{LOG_METHOD_EXECUTION}) {
150 1 50       4 die "log_config error: parameter LOG_METHOD_EXECUTION is not an array reference"
151             if ref $props->{LOG_METHOD_EXECUTION} ne 'ARRAY';
152 1         6 _log_subroutine_calls($self->log, @{$props->{LOG_METHOD_EXECUTION}});
  1         5  
153 1         3 delete $props->{LOG_METHOD_EXECUTION};
154             }
155              
156             # If there are still entries left in $props then they are invalid
157 7 50       33 die "Invalid option(s) (".join(', ', keys %$props).") passed to log_config" if %$props;
158             }
159              
160 7         577 $log_config;
161             }
162              
163             sub _log_subroutine_calls {
164 1     1   2 my $log = shift;
165             eval {
166 1         13 Sub::WrapPackages->require;
167             Sub::WrapPackages->import(
168             packages => [@_],
169             pre => sub {
170 4     4   41202 $log->debug("calling $_[0](".join(', ', @_[1..$#_]).")");
171             },
172             post => sub {
173 6     6   98 no warnings qw(uninitialized);
  6         13  
  6         5047  
174 4     4   172 $log->debug("returning from $_[0] (".join(', ', @_[1..$#_]).")");
175             }
176 1         36 );
177 1         260 1;
178 1 50       2 } or do {
179 0         0 $log->error("Failed to load and configure Sub::WrapPackages: $@");
180             };
181             }
182              
183             sub _append_newline {
184 11     11   1753 my %hash = @_;
185 11         30 chomp $hash{message};
186 11         60 return $hash{message}.$/;
187             }
188              
189              
190             ##
191             ## Private methods
192             ##
193             sub _set_object {
194 7     7   18 my $self = shift;
195 7         16 my $log = shift;
196 7 100       33 my $class = ref $self ? ref $self : $self;
197              
198 7 100       24 if (ref $self) {
199 5         19 $self->{__LOG_OBJECT} = $log;
200             } else {
201 6     6   39 no strict 'refs';
  6         11  
  6         1205  
202 2         4 ${$class.'::__LOG_OBJECT'} = $log;
  2         11  
203             }
204             }
205              
206             sub _get_object_or_options {
207 18     18   37 my $self = shift;
208 18 100       74 my $class = ref $self ? ref $self : $self;
209              
210             # Handle the simple case by looking in the object first
211 18 100       96 if (ref $self) {
212 17 100       199 return ($self->{__LOG_OBJECT}, undef) if $self->{__LOG_OBJECT};
213 10 100       62 return (undef, $self->{__LOG_CONFIG}) if $self->{__LOG_CONFIG};
214             }
215              
216             # See if we can find them in the class hierarchy
217             # We look at each of the modules in the @ISA tree, and
218             # their parents as well until we find either a log
219             # object or a set of configuration parameters
220 6         52 require Class::ISA;
221 6         33 foreach my $super ($class, Class::ISA::super_path($class)) {
222 6     6   33 no strict 'refs';
  6         11  
  6         2306  
223 7 100       686 return (${$super.'::__LOG_OBJECT'}, undef) if ${$super.'::__LOG_OBJECT'};
  4         22  
  7         46  
224 3 100       8 return (undef, ${$super.'::__LOG_CONFIG'}, $super) if ${$super.'::__LOG_CONFIG'};
  2         13  
  3         20  
225             }
226 0           return;
227             }
228              
229             sub _devpopup_report {
230 0     0     my $self = shift;
231 0           my $r=0;
232 0           my $history = join $/, map {
233 0           $r=1-$r;
234 0 0         qq(
$_->[0]$_->[1]
  0            
235             }
236 0           @{$self->{LOG_DISPATCH_DEVPOPUP_HISTORY}};
237 0           $self->devpopup->add_report(
238             title => 'Log Entries',
239             summary => 'All entries logged via Log::Dispatch',
240             report => qq(
241            
244            
245             $history
246            
LevelMessage
247            
248            
249            
250             ),
251             );
252             }
253              
254             1;
255             __END__