File Coverage

blib/lib/Log/Agent/Driver.pm
Criterion Covered Total %
statement 68 102 66.6
branch 8 10 80.0
condition 2 2 100.0
subroutine 15 25 60.0
pod 16 23 69.5
total 109 162 67.2


line stmt bran cond sub pod time code
1             ###########################################################################
2             #
3             # Driver.pm
4             #
5             # Copyright (C) 1999 Raphael Manfredi.
6             # Copyright (C) 2002-2017 Mark Rogaski, mrogaski@cpan.org;
7             # all rights reserved.
8             #
9             # See the README file included with the
10             # distribution for license information.
11             #
12             ##########################################################################
13              
14 14     14   99 use strict;
  14         26  
  14         19751  
15              
16             ########################################################################
17             package Log::Agent::Driver;
18              
19             #
20             # Ancestor for all Log::Agent drivers.
21             #
22              
23             #
24             # Common attribute acccess, initialized via _init().
25             #
26             # prefix the common (static) string info to prepend to messages
27             # penalty the skip Carp penalty to offset to the fixed one
28             #
29              
30 95     95 0 724 sub prefix { $_[0]->{'prefix'} }
31 37     37 0 88 sub penalty { $_[0]->{'penalty'} }
32              
33             #
34             # is_deferred
35             #
36             # Report routine as being deferred
37             #
38             sub is_deferred {
39 0     0 0 0 require Carp;
40 0         0 Carp::confess("deferred");
41             }
42              
43             #
44             # ->make -- deferred
45             #
46             # Creation routine.
47             #
48             sub make {
49 0     0 1 0 &is_deferred;
50             }
51              
52             #
53             # ->channel_eq
54             #
55             # Compare two channels and return true if they go to the same output.
56             #
57             sub channel_eq {
58 0     0 1 0 &is_deferred;
59             }
60              
61             #
62             # ->_init
63             #
64             # Common initilization routine
65             #
66             sub _init {
67 29     29   54 my $self = shift;
68 29         58 my ($prefix, $penalty) = @_;
69 29         110 $self->{'prefix'} = $prefix; # Prefix info to prepend
70 29         77 $self->{'penalty'} = $penalty; # Carp stack skip penalty
71             }
72              
73             #
74             # ->add_penalty -- "exported" only to Log::Agent::Driver::Datum
75             #
76             # Add offset to current driver penalty
77             #
78             sub add_penalty {
79 0     0 0 0 my $self = shift;
80 0         0 my ($offset) = @_;
81 0         0 $self->{penalty} += $offset;
82             }
83              
84             my %level = (
85             'c' => 1,
86             'e' => 2,
87             'w' => 4,
88             'n' => 6,
89             );
90              
91             #
92             # ->priority -- frozen
93             #
94             # Return proper priority for emit() based on one of the following strings:
95             # "critical", "error", "warning", "notice". Those correspond to the hardwired
96             # strings for logconfess()/logdie(), logerr(), logwarn() and logsay().
97             #
98             # This routine is intended to be "frozen", i.e. it MUST NOT be redefined.
99             # Redefine map_pri() if needed, or don't call it in the first place.
100             #
101             sub priority {
102 75     75 1 146 my $self = shift;
103 75         129 my ($prio) = @_;
104 75   100     313 my $level = $level{lc(substr($prio, 0, 1))} || 8;
105 75         180 return $self->map_pri($prio, $level);
106             }
107              
108             #
109             # ->write -- deferred
110             #
111             # Write log entry, physically.
112             # A trailing "\n" is to be added if needed.
113             #
114             # $channel is one of 'debug', 'output', 'error' and can be used to determine
115             # where the emission of the log message should be done.
116             #
117             sub write {
118 0     0 1 0 my $self = shift;
119 0         0 my ($channel, $priority, $logstring) = @_;
120 0         0 &is_deferred;
121             }
122              
123             #
124             # ->emit -- may be redefined
125             #
126             # Routine to call to emit log, resolve priority and prefix logstring.
127             # Ulitimately calls ->write() to perform the physical write.
128             #
129             sub emit {
130 75     75 1 133 my $self = shift;
131 75         168 my ($channel, $prio, $msg) = @_;
132 75         216 $self->write($channel, $self->priority($prio), $self->prefix_msg($msg));
133 75         486 return;
134             }
135              
136              
137             #
138             # ->map_pri -- may be redefined
139             #
140             # Convert a ("priority", level) tupple to a single priority token suitable
141             # for `emit'.
142             #
143             # This is driver-specific: drivers may ignore priority altogether thanks to
144             # the previous level-based filtering done (-trace and -debug switches in the
145             # Log::Agent configuration), choose to give precedence to levels over priority
146             # when "priority:level" was specified, or always ignore levels and only use
147             # "priority".
148             #
149             # The default is to ignore "priority" and "levels", which is suitable to basic
150             # drivers. Only those (ala syslog) which rely on post-filtering need to be
151             # concerned.
152             #
153             sub map_pri {
154 81     81 1 124 my $self = shift;
155 81         142 my ($priority, $level) = @_;
156 81         326 return ''; # ignored for basic drivers
157             }
158              
159             #
160             # ->prefix_msg -- deferred
161             #
162             # Prefix message with driver-specific string, if necessary.
163             #
164             # This routine may or may not use common attributes like the fixed
165             # static prefix or the process's pid.
166             #
167             sub prefix_msg {
168 0     0 1 0 my $self = shift;
169 0         0 my ($str) = @_;
170 0         0 &is_deferred;
171             }
172              
173             #
174             # ->carpmess
175             #
176             # Utility routine for logconfess and logcroak which builds the "die" message
177             # by calling the appropriate routine in Carp, and offseting the stack
178             # according to our call stack configuration, plus any offset.
179             #
180             sub carpmess {
181 37     37 0 78 my $self = shift;
182 37         76 my ($offset, $str, $fn) = @_;
183              
184             #
185             # While confessing, we have basically tell $fn() to skip 2 stack frames:
186             # this call, and our caller chain back to Log::Agent (calls within the
187             # same hierarchy are automatically stripped by Carp).
188             #
189             # To that, we add any additional penalty level, as told us by the creation
190             # routine of each driver, which accounts for extra levels used before
191             # calling us.
192             #
193              
194 37         139 require Carp;
195              
196 37         125 my $skip = $offset + 2 + $self->penalty;
197 37         64 $Carp::CarpLevel += $skip;
198 37         81 my $original = $str->str; # Original user message
199 37         5903 my $msg = &$fn('__MESSAGE__');
200 37         1675 $Carp::CarpLevel -= $skip;
201              
202             #
203             # If we have a newline in the message, we have a full stack trace.
204             # Replace the original message string with the first line, and
205             # append the remaining.
206             #
207              
208 37         79 chomp($msg); # Remove final "\n" added
209              
210 37 100       190 if ($msg =~ s/^(.*?)\n//) {
211 10         32 my $first = $1;
212              
213             #
214             # Patch incorrect computation by Carp, which occurs when we request
215             # a short message and we get a long one. In that case, what we
216             # want is the first line of the extra message.
217             #
218             # This bug manifests when the whole call chain above Log::Agent
219             # lies in "main". When objects are involved, it seems to work
220             # correctly.
221             #
222             # The kludge here is valid for perl 5.005_03. If some day Carp is
223             # fixed, we will have to test for the Perl version. The right fix,
224             # I believe, would be to have Carp skip frame first, and not last
225             # as it currently does.
226             # -- RAM, 30/09/2000
227             #
228              
229 10 50       37 if ($fn == \&Carp::shortmess) { # Kludge alert!!
230              
231             #
232             # And things just got a little uglier with 5.8.0
233             #
234             # -- mrogaski, 1 Aug 2002
235             #
236 10 50       29 my $index = $] >= 5.008 ? 1 : 0;
237              
238 10         70 $first =~ s/(at (.+) line \d+)$//;
239 10         25 my $bad = $1;
240 10         39 my @stack = split(/\n/, $msg);
241 10 100       80 my ($at) = $stack[$index] =~ /(at \S+ line \d+)$/
242             if defined $stack[$index];
243 10 100       37 $at = "$bad (Log::Agent could not fix it)" unless $at;
244 10         59 $first .= $at;
245 10         52 $str->set_str($first);
246             } else {
247 0         0 $str->set_str($first);
248 0         0 $str->append_last("\n");
249 0         0 $str->append_last($msg); # Stack at the very tail of message
250             }
251             } else {
252 27         83 $str->set_str($msg); # Change original message inplace
253             }
254              
255 37         95 $msg = $str->str;
256              
257             # Another Carp workaround kludge.
258 37         118 $msg =~ s/ at .*\d\.at / at /;
259              
260 37         127 $msg =~ s/__MESSAGE__/$original/;
261 37         105 $str->set_str($msg);
262              
263 37         97 return $str;
264             }
265              
266             #
267             # ->logcluck
268             #
269             # Warn with a full backtraace.
270             #
271             sub logcluck {
272 0     0 1 0 my $self = shift;
273 0         0 my ($str) = @_;
274 0         0 my $msg = $self->carpmess(0, $str, \&Carp::longmess);
275 0         0 $self->emit('error', 'warning', $msg);
276             }
277              
278             #
279             # ->logconfess
280             #
281             # Confess fatal error
282             # Error is logged, and then we confess.
283             #
284             sub logconfess {
285 0     0 1 0 my $self = shift;
286 0         0 my ($str) = @_;
287 0         0 my $msg = $self->carpmess(0, $str, \&Carp::longmess);
288 0         0 $self->emit('error', 'critical', $msg);
289 0         0 die "$msg\n";
290             }
291              
292             #
293             # ->logxcroak
294             #
295             # Fatal error, from the perspective of the caller.
296             # Error is logged, and then we confess.
297             #
298             sub logxcroak {
299 0     0 1 0 my $self = shift;
300 0         0 my ($offset, $str) = @_;
301 0         0 my $msg = $self->carpmess($offset, $str, \&Carp::shortmess);
302 0         0 $self->emit('error', 'critical', $msg);
303 0         0 die "$msg\n";
304             }
305              
306             #
307             # ->logdie
308             #
309             # Fatal error
310             # Error is logged, and then we die.
311             #
312             sub logdie {
313 2     2 1 4 my $self = shift;
314 2         4 my ($str) = @_;
315 2         6 $self->emit('error', 'critical', $str);
316 2         8 die "$str\n";
317             }
318              
319             #
320             # logerr
321             #
322             # Log error
323             #
324             sub logerr {
325 12     12 1 23 my $self = shift;
326 12         24 my ($str) = @_;
327 12         53 $self->emit('error', 'error', $str);
328             }
329              
330             #
331             # ->logxcarp
332             #
333             # Log warning, from the perspective of the caller.
334             #
335             sub logxcarp {
336 0     0 1 0 my $self = shift;
337 0         0 my ($offset, $str) = @_;
338 0         0 my $msg = $self->carpmess($offset, $str, \&Carp::shortmess);
339 0         0 $self->emit('error', 'warning', $msg);
340             }
341              
342             #
343             # logwarn
344             #
345             # Log warning
346             #
347             sub logwarn {
348 17     17 1 30 my $self = shift;
349 17         34 my ($str) = @_;
350 17         58 $self->emit('error', 'warning', $str);
351             }
352              
353             #
354             # logsay
355             #
356             # Log message at the "notice" level.
357             #
358             sub logsay {
359 18     18 1 31 my $self = shift;
360 18         38 my ($str) = @_;
361 18         52 $self->emit('output', 'notice', $str);
362             }
363              
364             #
365             # loginfo
366             #
367             # Log message at the "info" level.
368             #
369             sub loginfo {
370 1     1 0 2 my $self = shift;
371 1         3 my ($str) = @_;
372 1         2 $self->emit('output', 'info', $str);
373             }
374              
375             #
376             # logdebug
377             #
378             # Log message at the "debug" level.
379             #
380             sub logdebug {
381 2     2 0 4 my $self = shift;
382 2         4 my ($str) = @_;
383 2         11 $self->emit('output', 'debug', $str);
384             }
385              
386             #
387             # logwrite
388             #
389             # Emit the message to the specified channel
390             #
391             sub logwrite {
392 6     6 1 12 my $self = shift;
393 6         15 my ($chan, $prio, $level, $str) = @_;
394 6         21 $self->write($chan, $self->map_pri($prio, $level),
395             $self->prefix_msg($str));
396             }
397              
398             1; # for require
399             __END__