File Coverage

blib/lib/Fault/Logger.pm
Criterion Covered Total %
statement 21 184 11.4
branch 0 94 0.0
condition n/a
subroutine 7 30 23.3
pod 16 16 100.0
total 44 324 13.5


line stmt bran cond sub pod time code
1             #================================ Logger.pm ==================================
2             # Filename: Logger.pm
3             # Description: A fault handling logger
4             # Original Author: Dale M. Amon
5             # Revised by: $Author: amon $
6             # Date: $Date: 2008-08-28 23:20:19 $
7             # Version: $Revision: 1.12 $
8             # License: LGPL 2.1, Perl Artistic or BSD
9             #
10             # NOTE * Care must be taken that no matter what user API call is used
11             # first, LOGGER is initialized and the local $self or $s value is
12             # set to that. I do this by always calling _getargs before using
13             # self as an object pointer.
14             #
15             # * Every logging routine will call the internal method
16             # Fault::Logger->_log as the last thing it does, one way or the
17             # other. That is why it handles the update of the internal pointer
18             # to the last message actually logged.
19             #
20             #=============================================================================
21 1     1   5 use strict;
  1         1  
  1         36  
22 1     1   4 use POSIX;
  1         1  
  1         11  
23 1     1   7167 use Fault::Delegate::Stdout;
  1         3  
  1         120  
24 1     1   8 use Fault::Delegate::Stderr;
  1         2  
  1         27  
25 1     1   6 use Fault::Delegate::List;
  1         2  
  1         40  
26 1     1   7 use Fault::Msg;
  1         9  
  1         42  
27              
28             package Fault::Logger;
29 1     1   7 use vars qw{@ISA};
  1         1  
  1         3507  
30             @ISA = qw( UNIVERSAL );
31              
32             #=============================================================================
33             # Class Methods
34             #=============================================================================
35             my $LOGGER = undef;
36             my %once = ();
37              
38             sub new {
39 0     0 1   my ($class,@l) = @_;
40 0 0         $LOGGER || ($LOGGER = bless {}, $class);
41 0 0         @l || (@l = (Fault::Delegate::Stderr->new));
42 0           $LOGGER->{'message'} = undef;
43 0           %once = ();
44 0           $LOGGER->{'delegates'} = Fault::Delegate::List->new (@l);
45 0           return $LOGGER;
46             }
47              
48             #------------------------------------------------------------------------------
49              
50 0 0   0 1   sub delegates ($) {my $s=shift; $LOGGER || $s->new;
  0            
51 0           $LOGGER->{'delegates'}->delegates;}
52              
53 0 0   0 1   sub add_delegates ($@) {my ($s,@l) = @_; $LOGGER || $s->new;
  0            
54 0           $LOGGER->{'delegates'}->add (@l);}
55              
56 0 0   0 1   sub message ($) {$LOGGER || shift->new;
57 0 0         defined $LOGGER->{'message'} || return "";
58 0           return $LOGGER->{'message'}->msg;}
59              
60 0     0 1   sub clr_log_once ($) {%once = ();}
61 0 0   0 1   sub clr_message ($) {$LOGGER || shift->new; $LOGGER->{'message'} = undef;}
  0            
62              
63             #=============================================================================
64             # Bottom level logging methods
65             #=============================================================================
66              
67             sub log ($;$$$$@) {
68 0     0 1   my ($s,$msg,@rest) = _getargs(@_);
69 0           $s->_log ($msg,@rest);
70             }
71              
72             #------------------------------------------------------------------------------
73              
74             sub crash ($;$$$$@) {
75 0     0 1   my ($s,$msg,@rest) = _getargs(@_);
76              
77 0           $msg->set_prefix ("Fatal error");
78 0           $s->_log ($msg, @rest);
79 0           die ($msg->msg);
80             }
81              
82             #------------------------------------------------------------------------------
83              
84             sub log_once ($;$$$$@) {
85 0     0 1   my ($s,$msg,@args) = _getargs(@_);
86 0           $s->_oneshot($msg,@args);
87             }
88              
89             #=============================================================================
90             # Specialized logging methods
91             #=============================================================================
92              
93             sub fault_check ($$;$$$$$@) {
94 0     0 1   my ($self,$c,$tag,@args) = @_;
95 0           my ($s,$msg,@rest) = _getargs($self,@args);
96 0 0         $c = ($c) ? 1 : 0;
97              
98 0           $msg->set_tag($tag);
99 0           $s->_dflop ($c,$msg,@rest);
100 0           return !$c;
101             }
102              
103             #------------------------------------------------------------------------------
104              
105             sub assertion_check ($$;$$$$$@) {
106 0     0 1   my ($self,$c,$tag,@args) = @_;
107 0           my ($s,$msg,@rest) = _getargs($self,@args);
108 0 0         $c = ($c) ? 1 : 0;
109              
110 0           $msg->set_tag($tag);
111              
112 0 0         $s->_log($msg,@rest) if $c;
113 0           return !$c;
114             }
115              
116             #==============================================================================
117             # Bug check call sequence differs from all other calls and this could cause
118             # confusion.
119              
120             sub bug_check ($$;$$$$@) {
121 0     0 1   my ($self,$c,$m,@args) = @_;
122 0           my ($s,$msg,@rest) = _getargs($self,$m,'BUG','err',@args);
123 0 0         $c = ($c) ? 1 : 0;
124              
125 0           $msg->set_tag($s->_get_tag);
126 0           $s->_dflop ($c,$msg,@rest);
127 0           return !$c;
128             }
129              
130             #==============================================================================
131             # Argument check logging methods
132             #=============================================================================
133              
134             sub arg_check_isalnum ($$$;$$$@) {
135 0     0 1   my ($self,$v,$n,@args) = @_;
136 0           my ($m,$c) = ("",1);
137 0           $n = Fault::Logger->_validate_varname ($n);
138              
139 0 0         if (!defined $v) {$m = "\'$n\' is undefined.";}
  0 0          
  0 0          
140 0           elsif (ref $v) {$m = "\'$n\' should not be a pointer.";}
141 0           elsif (!POSIX::isalnum $v) {$m = "\'$n\' contains non alphanumeric characters: \'$v\'.";}
142             else {$c = 0;}
143              
144 0           my ($s,$msg,@rest) = _getargs($self,$m,@args);
145 0           $msg->set_tag($s->_get_tag);
146              
147 0 0         $s->_log($msg,@rest) if $c;
148 0           return !$c;
149             }
150              
151             #------------------------------------------------------------------------------
152              
153             sub arg_check_isdigit ($$$;$$$@) {
154 0     0 1   my ($self,$v,$n,@args) = @_;
155 0           my ($m,$c) = ("",1);
156 0           $n = Fault::Logger->_validate_varname ($n);
157              
158 0 0         if (!defined $v) {$m = "\'$n\' is undefined.";}
  0 0          
  0 0          
159 0           elsif (ref $v) {$m = "\'$n\' should not be a pointer.";}
160 0           elsif (!POSIX::isdigit $v) {$m = "\'$n\' contains non digit characters: \'$v\'.";}
161             else {$c = 0;}
162              
163 0           my ($s,$msg,@rest) = _getargs($self,$m,@args);
164 0           $msg->set_tag($s->_get_tag);
165              
166 0 0         $s->_log($msg,@rest) if $c;
167 0           return !$c;
168             }
169              
170             #------------------------------------------------------------------------------
171              
172             sub arg_check_noref ($$$;$$$@) {
173 0     0 1   my ($self,$v,$n,@args) = @_;
174 0           my ($m,$c) = ("",1);
175 0           $n = Fault::Logger->_validate_varname ($n);
176              
177 0 0         if (!defined $v) {$m = "\'$n\' is undefined.";}
  0 0          
  0            
178 0           elsif (ref $v) {$m = "\'$n\' should not be a pointer.";}
179             else {$c = 0;}
180              
181 0           my ($s,$msg,@rest) = _getargs($self,$m,@args);
182 0           $msg->set_tag($s->_get_tag);
183              
184 0 0         $s->_log($msg,@rest) if $c;
185 0           return !$c;
186             }
187              
188             #------------------------------------------------------------------------------
189             my %refs = ('REF'=>1,'SCALAR'=>1,'ARRAY'=>1,'HASH'=>1,'CODE'=>1,'GLOB'=>1);
190              
191             sub arg_check_isa ($$$$;$$$@) {
192 0     0 1   my ($self,$v,$class,$n,@args) = @_;
193 0           my ($m,$c) = ("",1);
194 0           $n = Fault::Logger->_validate_varname ($n);
195 0           $class = Fault::Logger->_validate_classname ($class);
196              
197 0 0         if (!defined $v) {$m = "\'$n\' is undefined.";}
  0 0          
  0            
198             elsif (!ref $v) {$m = "\'$n\' is not a reference.";}
199             else {
200 0 0         if (defined $refs{ref $v}) {
  0 0          
201 0 0         if (ref $v ne $class) {$m = "\'$n\' is not a $class.";}
  0            
  0            
202             else {$c = 0;}
203             }
204 0           elsif (!$v->isa($class)) {$m = "\'$n\' is not a $class.";}
205             else {$c = 0;}}
206              
207 0           my ($s,$msg,@rest) = _getargs($self,$m,@args);
208 0           $msg->set_tag($s->_get_tag);
209              
210 0 0         $s->_log($msg,@rest) if $c;
211 0           return !$c;
212             }
213              
214             #=============================================================================
215             # Internal Methods
216             #=============================================================================
217             # Handle 'edge-triggered' logging.
218              
219             sub _dflop ($$$;$$$@) {
220 0     0     my ($s,$c,$msg,@rest) = @_;
221            
222 0           my $list = $s->{'delegates'};
223 0           my $prev = $list->fault_exists($msg);
224 0 0         my $cur = ($c) ? 1 : 0;
225 0           my $state = ($prev<<1) + $cur;
226 0           my $chng = 0;
227            
228 0           SWITCH: {
229 0 0         if ($state == 0) {$list->trans00($msg,@rest); last;}
  0            
  0            
230            
231 0 0         if ($state == 1) {$chng = 1;
  0            
232 0           $list->trans01($msg,@rest);
233 0           $msg->set_prefix("FAULT RAISED"); last;}
  0            
234            
235 0 0         if ($state == 2) {$chng = 1;
  0            
236 0           $list->trans10($msg,@rest);
237 0           $msg->set_prefix("FAULT CLEARED"); last;}
  0            
238            
239 0 0         if ($state == 3) {$list->trans11($msg,@rest); last;}
  0            
  0            
240             }
241            
242 0 0         $s->_log ($msg,@rest) if ($chng);
243 0           return !$c;
244             }
245              
246             #------------------------------------------------------------------------------
247             # Handle 'one-shot' logging.
248              
249             sub _oneshot ($$;$$$@) {
250 0     0     my ($s,$msg,@rest) = @_;
251 0 0         !$once{$msg->msg} || (return 0);
252 0           $once{$msg->msg} = 1;
253 0           $s->_log ($msg,@rest);
254 0           return 1;
255             }
256              
257             #------------------------------------------------------------------------------
258             # Internal validation and convenience methods
259             #------------------------------------------------------------------------------
260             # Log a message unconditionally. This routine updates the pointer to the
261             # last message object logged.
262              
263             sub _log ($$@) {
264 0     0     my ($s,$msg,@rest) = @_;
265 0           $s->{'message'} = $msg;
266 0           $s->{'delegates'}->log ($msg,@rest);
267             }
268              
269             #------------------------------------------------------------------------------
270             sub _get_tag {
271 0     0     my $self = shift;
272 0           my $tag;
273 0           my ($package, $filename, $line, $subroutine) = caller(2);
274 0 0         if (defined $subroutine) {
  0 0          
    0          
275 0           my @name = split '::',$subroutine;
276 0           my $mname = pop @name;
277 0           my $cname = join '::', @name;
278 0 0         $tag = ($cname) ? "[$cname->$mname()]" : $mname;
279             }
280 0           elsif (defined $package) {$tag = "[$package]";}
281 0           elsif (defined $filename) {$tag = "[$filename]";}
282             else {$tag = "[Main]";}
283 0           return "$tag ";
284             }
285              
286             #------------------------------------------------------------------------------
287              
288             sub _getargs ($;$$$@) {
289 0     0     my ($s,$m,$t,$p,@rest) = @_;
290 0 0         $LOGGER || $s->new;
291              
292 0           my $msg = Fault::Msg->new ($m,$t,$p);
293              
294 0 0         if ($msg->is_blank) {
295 0           my $tag = $LOGGER->_get_tag;
296 0           $msg->set_msg ("${tag}No message argument");
297             }
298 0           return ($LOGGER,$msg,@rest);
299             }
300              
301             #------------------------------------------------------------------------------
302              
303             sub _validate_varname ($@) {
304 0     0     my ($s,$n) = @_;
305              
306 0 0         if (!defined $n ) {$n = "Unnamed variable";}
  0 0          
  0 0          
307 0           elsif (ref $n ) {$n = "Invalid variable name (Pointer)";}
308             elsif (!POSIX::isprint $n) {$n = "Invalid variable name " .
309             "(Not printable)";}
310 0           return ucfirst $n;
311             }
312              
313             #------------------------------------------------------------------------------
314              
315             sub _validate_classname ($@) {
316 0     0     my ($s,$class) = @_;
317              
318 0 0         if (!defined $class ) {$class = 'HASH';}
  0 0          
  0 0          
319 0           elsif (ref $class) {$class =
320             'FaultyClassname-CannotBeAPointer';
321 0           Fault::ErrorHandler->warn
322             ("Class cannot be a pointer.");}
323             elsif (!POSIX::isprint $class) {Fault::ErrorHandler->warn
324             ("Class contains non-printable char: " .
325             "\'$class\'.");
326 0           $class =
327             'FaultyClassname-Unprintable';}
328 0           return $class;
329             }
330            
331             #=============================================================================
332             # Pod Documentation
333             #=============================================================================
334             # You may extract and format the documentation section with the 'perldoc' cmd.
335              
336             =head1 NAME
337              
338             Fault::Logger - A message logger proxy.
339              
340             =head1 SYNOPSIS
341              
342             use Fault::Logger;
343             $proxy = Fault::Logger->new (@delegates);
344             $proxy = Fault::Logger->new;
345             @delegates = Fault::Logger->delegates;
346             @delegates = $proxy->delegates;
347             $one = Fault::Logger->add_delegates (@delegates);
348             $one = $proxy->add_delegates (@delegates);
349              
350             $msg = Fault::Logger->message;
351             $msg = $proxy->message;
352             Fault::Logger->clr_message;
353             $proxy->clr_message;
354              
355             Fault::Logger->clr_log_once;
356             $proxy->clr_log_once;
357              
358             $didlog = Fault::Logger->log ($m,$t,$p,$o,@rest);
359             $didlog = $proxy->log ($m,$t,$p,$o,@rest);
360             Fault::Logger->crash ($m,$t,$p,$o,@rest);
361             $proxy->crash ($m,$t,$p,$o,@rest);
362             $firsttime = Fault::Logger->log_once ($m,$t,$p,$o,@rest);
363             $firsttime = $proxy->log_once ($m,$t,$p,$o,@rest);
364              
365             $notfault = Fault::Logger->fault_check ($c,$tag,$m,$t,$p,$o,@rest);
366             $notfault = $proxy->fault_check ($c,$tag,$m,$t,$p,$o,@rest);
367             $notfault = Fault::Logger->assertion_check ($c,$tag,$m,$t,$p,$o,@rest);
368             $notfault = $proxy->assertion_check ($c,$tag,$m,$t,$p,$o,@rest);
369              
370             $notfault = Fault::Logger->arg_check_isalnum ($v,$varname,$t,$p,$o,@rest);
371             $notfault = $proxy->arg_check_isalnum ($v,$varname,$t,$p,$o,@rest);
372              
373             $notfault = Fault::Logger->arg_check_isdigit ($v,$varname,$t,$p,$o,@rest);
374             $notfault = $proxy->arg_check_isdigit ($v,$varname,$t,$p,$o,@rest);
375              
376             $notfault = Fault::Logger->arg_check_noref ($v,$varname,$t,$p,$o,@rest);
377             $notfault = $proxy->arg_check_noref ($v,$varname,$t,$p,$o,@rest);
378              
379             $notfault = Fault::Logger->arg_check_isa ($v,$class,$varname,$t,$p,$o,@rest);
380             $notfault = $proxy->arg_check_isa ($v,$class,$varname,$t,$p,$o,@rest);
381              
382             $notfault = Fault::Logger->bug_check ($c,$m,$t,$p,$o,@rest);
383             $notfault = $proxy->bug_check ($c,$m,$t,$p,$o,@rest);
384              
385             =head1 Inheritance
386              
387             Base Class
388              
389             =head1 Description
390              
391             This Class does not have instance objects, only a single 'Class Object'. As
392             it may be referenced by class name, it is very easy for code at any level or
393             location within a system to find it and thus send messages to a central
394             logging point. The actual logging is handled by a user specified and easily
395             changed list of delegates so the logging behavior and destinations of your
396             entire program is modifiable at run-time.
397              
398             Since the actual logging is handled by a user delegate, you may ask, then
399             what is the point of Logger? Logger is a controller. It provides the structure
400             within which more sophisticated logging may be done.
401              
402             Defaulting is central to the philosophy of the design. A mistake in the
403             args to your rarely used log or fault call should not prevent at least
404             I from being printed to let you know something happened. Crashing
405             is not an option.
406              
407             Logger currently provides four different types of logging:
408              
409             =head2 Simple logging
410              
411             This is what most people have in mind. You call a routine, and it sends a
412             message somewhere. What Logger adds to this most basic process is the ability
413             to use different destinations in different part of your program or to mix and
414             match them as you wish. If you provide a delegate that handles output to files,
415             you log to file; if it sets up syslog, you log the same message to syslog; if
416             you set up a MySQL table then your delegate can log to that. All you need to
417             handle in your delegate code is the moving of a message from your input onto
418             one or more outputs. Logger passes through arguments unique to your delegate.
419              
420             The user's program must of course have write privileges to where their object
421             intends to log, whether it be file, syslog, database table or whatever.
422              
423             Simple logging methods are log and crash.
424              
425             =head2 Log once
426              
427             There are times when you want to see if a particular condition happens, but
428             you know that if it does it will recur at a high rate. The log_once method
429             does just this. It keeps track of each string passed through it for logging
430             and if that string has already been seen it returns immediately without
431             logging anything.
432              
433             If you initialize the Logger via new it will also clear the list of logged
434             messages kept up by log_once. You may also clear it with the clr_log_once
435             method.
436              
437             =head2 Conditional logging
438              
439             It is quite often the case that you want to log a message every time some
440             condition is true. This is the sort of thing which is done when you put
441             diagnostic assertions into your code. You only want output if the assertion
442             is true. For convenience we have assertion_check and a family of similar
443             methods. They embed the condition flag (or an entire expression) in the method
444             call so that you needn't construct a whole list of conditionals. In case
445             you still require a conditional action, the subroutine returns the inverse
446             of the value it tested. This will make it useful in common statements of
447             the form: expression-a || expression-b.
448              
449             =head2 Change of state logging
450              
451             The most sophisticated use and one of the primary reasons for Logger is the
452             management of 'edge-triggered' logging. The message text is used as a unique
453             identifier. (It is thus not wise to do this sort of logging on messages with
454             a non-repeatable component like the address of a variable). The full message
455             is stored when first seen in conjunction with a true condition test; it is
456             removed when the same text is seen with the condition test false. Changing
457             from false to true causes the message to be logged as 'fault raised'; going
458             from true to false logs a 'fault cleared' message.
459              
460             The fault_check and bug_check methods are of this type.
461              
462             There are also hooks supplied so that a user's delegate class may be called
463             during initialization and at any or all transitions: false-false; false-true;
464             true-true; true-false. You probably would only be interested in the false-true
465             and true-false edge-transitions.
466              
467             With this method you can construct systems to display and remove fault messages
468             in real time as conditions occur and are fixed.
469              
470             All of the Logger methods accept and pass through a target object pointer as
471             the second argument. This allows a calling object to pass a callback pointer
472             to itself through the Logger to the delegate object. The delegate object is
473             then free to communicate whatever it wishes with the object which declared the
474             error. It might write a copy of the log message into the target, or it might
475             try to fix something. What happens is in the hands of the delegate writer.
476             Logger only supplies the framework.
477              
478             Logger also passes through a type argument in all calls, although it may be
479             defaulted in most cases. To be truthful, this exists for my own database
480             application, but it may be of use to others as well. It is intended to be used
481             as a simple classifier of messages.
482              
483             The definition of type names are left (mostly) to the user to define and
484             utilize. Currently Logger only demands one type be recognized: "BUG". You will
485             see this in your delegate if you use bug_check or default the type argument
486             in fault_check.
487              
488             =head2 Logger delegate protocol
489              
490             We have made much of delegates in the previous discussion. But exactly what
491             is a delegate? How do you write one?
492              
493             Most basically, a Logger delegate is any instance of a Class that accepts a
494             method call of the form:
495              
496             $didlog = $delegate->log ($msg,$o,@rest)
497              
498             Where $msg is the Fault::Msg object being processed by Logger; $o is a
499             callback pointer called the 'target', optionally passed in by the original
500             caller of a Logger method; and @rest is any additional arguments which the
501             Logger method received beyond those it uses itself.
502              
503             It should return $didlog true if $msg is successfully logged and false if it
504             was not. In the examples below, the Simple class implements this most minimal
505             delegate.
506              
507             This is a very useful capability. You can switch between using direct writes
508             to logfiles to logging remotely, logging via a Unix socket to syslog, or even
509             logging to a database table. The behavior is dependent on the capabilities of
510             the delegate class passed to the Logger proxy.
511              
512             In addition to the log method, delegates may define a number of other
513             'callback' or 'hook' methods. In Objective C on NeXT computers this sort of
514             thing is called a protocol.
515              
516             The user may seed the fault table with an initial set of messages (perhaps
517             ones previously saved in a database) by providing an initfaults method:
518              
519             @list = $delegate->initfaults
520              
521             The list should be a simple list of fault messages
522              
523             ("fault msg 1", "fault msg 2"...)
524            
525             as previously captured via a trans01 method. The user may supply callbacks
526             for any or all of the four possible fault transition states:
527              
528             $delegate->trans00 ($msg,$o,@rest)
529             $delegate->trans01 ($msg,$o,@rest)
530             $delegate->trans10 ($msg,$o,@rest)
531             $delegate->trans11 ($msg,$o,@rest)
532              
533             where $msg and $o are as described above and @rest are any private arguments
534             the user passed into the logger call.
535              
536             A method name will not be called unless it exists, so in most cases either none
537             of the above or only trans01 and trans10 need be defined. The return value is
538             not defined and will be ignored.
539              
540             The meanings of the transitions are:
541              
542             00 No fault, no change.
543             01 A new fault has occurred.
544             10 An existing fault has cleared.
545             11 Known fault, no change.
546              
547             You may also wish to examine the code of the various Fault::Delegate
548             classes provided as examples and a quick start.
549              
550             =head2 Argument definitions
551              
552             A number of arguments are standard and used in most of the callbacks defined
553             by this delegate.
554              
555             =over 4
556             A message is a nearly arbitrary text string of arbitrary length. It should
557             not contain page formatting characters like formfeed, newline, etc. In practice
558             the length may be limited by the web server you are communicating with.
559              
560             A Type is a single arbitrary capitalized word. You may add your own, but
561             this is the required subset.
562              
563             BUG For programming faults.
564             DATA Anything to do with file data or directories.
565             SRV Server operational issues, startup, login,
566             initializing. Hardware failures.
567             NET Failure to connect to a host, connectivity issues.
568             NOTE Reporting things of interest. Restarts, normal
569             operational info.
570             other The user may define any additional single word tags
571             they desire and they will be treated equally to the
572             required set.
573              
574             If you use types not in this list, it is up to your web logger to accept
575             them. You must accept any of the default list, but what you do with them
576             or your own afterwards is up to you. Types help to categorize messages
577             rather than define how important they are. You can have any 'type' of log
578             messages reporting at any 'priority'.
579              
580             A priority must be one of the Unix syslog priorities:
581              
582             emerg Off the scale.
583             alert A major subsystem is unuseable.
584             crit A critical subsystem is not working entirely.
585             err Bugs, bad data, files not found, things that went
586             bump in the night.
587             warning Something that should be attended to but that is not really
588             an error.
589             notice The standard reports people want to read.
590             info Ordinarily unneeded chatter that is useful if
591             trouble-shooting is needed after the fact.
592             debug Really boring diagnostic output.
593              
594             If a subclass has no means of doing anything with priority, it may be left
595             out. All the arguments before it must be handled and if necessary defaulted
596             to reasonable values by a subclass.
597              
598             If you do specify a type but not a priority in an arg list, for whatever
599             reason, priority will default as follows:
600              
601             BUG err
602             DATA warning
603             SRV warning
604             NET warning
605             NOTE info
606             other warning
607              
608             If there is no type both arguments will default, resulting in type equal
609             'BUG' and priority equal 'err'.
610              
611             A target is an object reference. If present it is passed unexamined to the
612             subclass. A target could be used to return log state information to the
613             site at which the log or fault occurred.
614              
615             As many additional subclass specific arguments as you wish may be added
616             after the priority argument position in the calling sequences. They
617             are passed straight through with no processing or checking.
618              
619             =back 4
620              
621             Besides these explicit arguments the delegate checks for the existence of
622             a global variable:
623              
624             $::PROCESS_NAME
625              
626             If used, this should contain a single word name for your process. If the
627             process name contains spaces, use underscore as a replacement for them. For
628             example:
629              
630             $::PROCESS_NAME = "MyProcess";
631             $::PROCESS_NAME = "My_Process";
632              
633             If this global is undefined a default of "UnspecifiedProcess" is used as fault
634             processing depends upon it. Further, the value is retrieved in each method
635             just before use to cover the case of spawned processes whose names are
636             different from that of the parent process.
637              
638             =head1 Examples
639              
640             =head2 Example 1: Default everything
641              
642             use Fault::Logger;
643             Fault::Logger->log ("test logging");
644              
645             =head2 Example 2: Multiple delegates
646              
647             use Fault::Logger;
648             use Fault::Delegate::Stdout;
649             use Fault::Delegate::Stderr;
650             use Fault::Delegate::Syslog;
651             use Fault::Delegate::File;
652              
653             my $delegate1 = Fault::Delegate::Stdout->new;
654             my $delegate2 = Fault::Delegate::Syslog->new;
655             my $delegate3 = Fault::Delegate::File->new ("/tmp/test.log");
656              
657             my @delegates = ($delegate1,$delegate2,$delegate3);
658             Fault::Logger->new (@delegates);
659             Fault::Logger->log ("test logging",'NOTE','warning');
660              
661              
662             =head2 Example 3: Fault monitoring
663              
664             use Fault::Logger;
665             use Fault::Delegate::DB;
666              
667             # Works only if you have the Log and Fault Tables set up in mydbname.
668             # [see Fault::Delegate::DB]
669             my $delegate1 = Fault::Delegate::DB->new (undef,"mydbname","user","passwd");
670             Fault::Logger->new ($delegate1);
671              
672             # Set a fault
673             my $fail = 0;
674             Fault::Logger->fault_check
675             (!defined $foo,"Optional tag","No foo!",'BUG','err') or return $fail;
676              
677             # Clear a fault
678             my $foo = 1;
679             Fault::Logger->fault_check
680             (!defined $foo,"Optional tag","No foo!",'BUG','err') or return $fail;
681            
682             [See example.pl for a bigger sample. It can be found either in eg/example.pl
683             in your Perl package or /var/share/doc/libfault-perl/example.pl if installed
684             from a debian package.]
685              
686             =head1 Class Variables
687              
688             delegates An object which satisfies a minimal logger delegate protocol.
689             It must at the very least implement the log method.
690             message The mostly recently logged message. the null string if cleared
691             or there has been none since the logger was last initialized.
692              
693             =head1 Instance Variables
694              
695             None.
696              
697             =head1 Class Methods
698              
699             =over 4
700              
701             =item B<$proxy = Fault::Logger-Enew (@delegates)>
702              
703             =item B<$proxy = Fault::Logger-Enew>
704              
705             Initialize the logger proxy if it has never been called before and
706             return a pointer to it in any case. There is only one logger object,
707             a class object, and further calls simply return the same pointer. It
708             can be accessed either by classname or the returned pointer.
709              
710             By supplying a list of one or more delegate objects, you modify where and
711             how your program will log and fault. The defaults is a Fault::Delegate::Stderr
712             object if no delegate is supplied the first time new is called. On any
713             subsequent calls, the default is to leave the delegate object as is.
714              
715             Calling this routine re-initializes the logger object. it clears log once
716             entries, previous log delegates and the internal fault table. If
717             the any of the new delegates have initfaults methods, they are used to
718             retrieve any active faults. If the delegate has a method of keeping
719             persistant data, programs can be stopped and started without forgetting
720             about active faults.
721              
722             =item B<$one = Fault::Logger-Eadd_delegates (@delegates)>
723              
724             =item B<$one = $proxy-Eadd_delegates (@delegates)>
725              
726             Add zero or more logger delegates. A delegate object is ignored if it
727             is already present.
728              
729             =item B<$notfault = Fault::Logger-Earg_check_isa ($val,$class,$name,$type,$priority,$target,@rest)>
730              
731             =item B<$notfault = $proxy-Earg_check_isa ($val,$class,$name,$type,$priority,$target,@rest)>
732              
733             If the value $val of the variable named $name is undefined, is a not a
734             reference or is not a member of $class or one of its subclasses, log an
735             appropriate message. The message will contain the name of the subroutine or
736             class and method of the caller. Class defaults to 'HASH' if not present.
737             Other values default as documented in the Argument Description section.
738              
739             This method is useful for checking subroutine args.
740              
741             =item B<$notfault = Fault::Logger-Earg_check_isalnum ($val,$name,$type,$priority,$target,@rest)>
742              
743             =item B<$notfault = $proxy-Earg_check_isalnum ($val,$name,$type,$priority,$target,@rest)>
744              
745             If the value $val of the variable named $name is undefined, is a reference or
746             contains a nonalphnumeric character, log an appropriate message. The message
747             will contain the name of the subroutine or class and method of the caller. Type
748             defaults to BUG if not present.
749              
750             This method is useful for checking subroutine args.
751              
752             =item B<$notfault = Fault::Logger-Earg_check_isdigit ($val,$name,$type,$priority,$target,@rest)>
753              
754             =item B<$notfault = $proxy-Earg_check_isdigit ($val,$name,$type,$priority,$target,@rest)>
755              
756             If the value $val of the variable named $name is undefined, is a reference or
757             contains a non digit characters log an appropriate message. The message will
758             contain the name of the subroutine or class and method of the caller. Type
759             defaults to BUG if not present.
760              
761             This method is useful for checking subroutine args.
762              
763             =item B<$notfault = Fault::Logger-Earg_check_noref ($val,$name,$type,$priority,$target,@rest)>
764              
765             =item B<$notfault = $proxy-Earg_check_noref ($val,$name,$type,$priority,$target,@rest)>
766              
767             If the value $val of the variable named $name is undefined or is a reference
768             or not alphanumeric, log an appropriate message. The message will contain the
769             name of the subroutine or class and method of the caller. Type defaults to BUG
770             if not present.
771              
772             This method is useful for checking subroutine args.
773              
774             =item B<$notfault = Fault::Logger-Eassertion_check ($cond,$tag,$msg,$type,$priority,$target,@rest)>
775              
776             =item B<$notfault = $proxy-Eassertion_check ($cond,$tag,$msg,$type,$priority,$target,@rest)>
777              
778             If the condition flag is true log the message. This is much like log except
779             it encapsulates the condition test. This is useful if you want to log the
780             testing of assertions sprinkled through your code. It does nothing if $cond
781             is false or undefined.
782              
783             =item B<$notfault = Fault::Logger-Ebug_check ($cond,$msg,$target,@rest)>
784              
785             =item B<$notfault = $proxy-Ebug_check ($cond,$msg,$target,@rest)>
786              
787             Set or clear a bug fault report.
788              
789             If $cond is defined and true, a fault defined by $tag and $msg is now active;
790             it is false or undefined, that fault is now inactive.
791              
792             The return value is the inverse of $cond: it is true if there was no fault
793             and false if there was. This makes the function useful in statements like:
794              
795             Fault::Logger->bug_check(@arglist) || (return undef);
796             or
797             return Fault::Logger->bug_check(@arglist);
798              
799             Note that your methods will always receive type equal "BUG" and a priority of
800             'err' from this method. So...
801              
802             I
803             that of all the other methods. You have been warned.>
804              
805             =item Bclr_log_once>
806              
807             =item B<$proxy-Eclr_log_once>
808              
809             Flush the 'log once' table. Doing this will allow those messages to be logged
810             again. Sometimes useful in debugging. I can imagine running it once a day
811             so as to see if some problems are still present or have gone away.
812              
813             =item Bclr_message>
814              
815             =item B<$proxy-Eclr_message>
816              
817             Clear the most recently logged message by setting it to a null string.
818              
819             =item Bcrash ($msg,$type,$priority,$target,@rest)>
820              
821             =item B<$proxy-Ecrash ($msg,$type,$priority,$target,@rest)>
822              
823             The message "Fatal error: $msg" is sent to the delegate and then calls die
824             with the same message.
825              
826             =item B<@delegates = Fault::Logger-Edelegates>
827              
828             =item B<@delegates = $proxy-Edelegates>
829              
830             Return the list of logger delegates.
831              
832             =item B<$notfault = Fault::Logger-Efault_check ($cond,$tag,$msg,$type,$priority,$target,@rest)>
833              
834             =item B<$notfault = $proxy-Efault_check ($cond,$tag,$msg,$type,$priority,$target,@rest)>
835              
836             This method provides 'edge triggered' fault handling. It should be called
837             every time an action is taken, not just when there is an error. $cond is an
838             expression which tests your fault condition, where true means fault and
839             anything else means there is no fault condition. When a new fault arises, a
840             message of the form:
841              
842             [FAULT RAISED] $msg
843              
844             will be printed. When $cond is next false with the same message, the fault is
845             considered cleared:
846              
847             [FAULT CLEARED] $msg
848              
849             This is useful for monitoring of systems as it can keep track of many unique
850             fault conditions at a low level with very little code overhead in the user's
851             program. As an example:
852              
853             Fault::Logger->fault_check
854             (((-e $fn) ? 1 : 0), $self,
855             "Ignored: \"$fn\" already exists.", "NOTE",
856             @rest);
857              
858             the condition expression may be anything which can be interpreted as a logical
859             value:
860              
861             (!open ($fd,"
862              
863             If $cond is defined and true, a fault defined by $tag and $msg is now active;
864             it is false or undefined, that fault is now inactive.
865              
866             =item B<$waslogged = Fault::Logger-Elog ($msg,$type,$priority,$target,@rest)>
867              
868             =item B<$waslogged = $proxy-Elog ($msg,$type,$priority,$target,@rest)>
869              
870             All arguments are sent to the delegate object via its log method and the
871             return value of the delegate method is the return value here. If the message
872             cannot be logged (the delegate returns false), the message is sent to a
873             default logger and false is returned.
874              
875             =item B<$firsttime = Fault::Logger-Elog_once ($msg,$type,$priority,$target,@rest)>
876              
877             =item B<$firsttime = $proxy-Elog_once ($msg,$type,$priority,$target,@rest)>
878              
879             Log a message if it has never appeared before; otherwise ignore it. Returns
880             true if this is the first time; false in all other cases.
881              
882             =item B<$msg = Fault::Logger-Emessage>
883              
884             =item B<$msg = $proxy-Emessage>
885              
886             Return the most recently logged message or else the null message if nothing
887             has been logged yet or it has been explicitly cleared.
888              
889             =back 4
890              
891             =head1 Instance Methods
892              
893             None.
894              
895             =head1 Private Class Methods
896              
897             None.
898              
899             =head1 Private Instance Methods
900              
901             None.
902              
903             =head1 Errors and Warnings
904              
905             None.
906              
907             =head1 KNOWN BUGS
908              
909             See TODO.
910              
911             =head1 SEE ALSO
912              
913             Fault::Delegate, Fault:Delegate::Stdout, Fault:Delegate::Stderr,
914             Fault:Delegate::File, Fault:Delegate::Syslog, Fault:Delegate::DB,
915             Fault:Delegate::SimpleHttp, Fault::Delegate::List
916              
917             =head1 AUTHOR
918              
919             Dale Amon
920              
921             =cut
922            
923             #=============================================================================
924             # CVS HISTORY
925             #=============================================================================
926             # $Log: Logger.pm,v $
927             # Revision 1.12 2008-08-28 23:20:19 amon
928             # perldoc section regularization.
929             #
930             # Revision 1.11 2008-08-17 21:56:37 amon
931             # Make all titles fit CPAN standard.
932             #
933             # Revision 1.10 2008-07-24 21:17:24 amon
934             # Moved all todo notes to elsewhere; made Stderr the default delegate instead of Stdout.
935             #
936             # Revision 1.9 2008-07-23 22:32:51 amon
937             # chomp line ends in Msg class rather than fail unconditionally due to
938             # POSIX::isprint.
939             #
940             # Revision 1.8 2008-05-10 15:19:44 amon
941             # Minor doc changes before release
942             #
943             # Revision 1.7 2008-05-09 18:24:55 amon
944             # Bugs and changes due to pre-release testing
945             #
946             # Revision 1.6 2008-05-08 20:22:50 amon
947             # Minor bug fixes; shifted fault table and initfault from Logger to List
948             #
949             # Revision 1.5 2008-05-07 19:22:05 amon
950             # Last major change set for this version.
951             #
952             # Revision 1.4 2008-05-05 19:25:49 amon
953             # Catch any small changes before implimenting major changes
954             #
955             # Revision 1.3 2008-05-04 14:38:46 amon
956             # Major rework of code and docs. First cut at multiple delegates and arg
957             # checking. Regularized call arg and return value lists.
958             #
959             # Revision 1.2 2008-05-03 00:36:01 amon
960             # Changed standard arg list. Also now defaults to Stdout delegate if none is
961             # supplied.
962             #
963             # Revision 1.1.1.1 2008-05-02 16:32:30 amon
964             # Fault and Log System. Pared off of DMA base lib.
965             #
966             # Revision 1.8 2008-04-25 10:58:13 amon
967             # documentation changes
968             #
969             # Revision 1.7 2008-04-20 00:58:26 amon
970             # Added the arg_check-* method set
971             #
972             # Revision 1.6 2008-04-18 14:07:54 amon
973             # Minor documentation format changes
974             #
975             # Revision 1.5 2008-04-11 22:25:23 amon
976             # Add blank line after cut.
977             #
978             # Revision 1.4 2008-04-11 18:56:35 amon
979             # Fixed quoting problem with formfeeds.
980             #
981             # Revision 1.3 2008-04-11 18:39:15 amon
982             # Implimented new standard for headers and trailers.
983             #
984             # Revision 1.2 2008-04-10 15:01:08 amon
985             # Added license to headers, removed claim that the documentation section still
986             # relates to the old doc file.
987             #
988             # Revision 1.1.1.1 2006-09-09 18:15:14 amon
989             # Dale's library of primitives in Perl
990             #
991             # 20041130 Dale Amon
992             # Almost a full rewrite over the last couple days. Added
993             # caller callback arg; changed name of logfile method
994             # to delegate; added more arg checking; split methods into
995             # public and private parts and more. Also redocumented.
996             #
997             # 20041127 Dale Amon
998             # Lots of additions. Added callback hooks for state
999             # transitions and pass throughs for args needed by syslog
1000             # using LogFile objects.
1001             #
1002             # 20041013 Dale Amon
1003             # Added crash method and support for arglist pass through.
1004             #
1005             # 20040813 Dale Amon
1006             # Moved to DMA:: from Archivist::
1007             # to make it easier to enforce layers.
1008             #
1009             # 20030108 Dale Amon
1010             # Changed to allow subclassing; general tidying; fixed LogFile
1011             # class to return t/f as assert in our log method.
1012             #
1013             # 20030107 Dale Amon
1014             # Created.
1015             #
1016             # DONE * Before I go public I should move the target variable to at least
1017             # before the type. I would have to change nearly all code I have
1018             # written this decade to do so. Is it worth it? Perhaps do a full
1019             # version split and grandfather the old ones? Perhaps rename the
1020             # new one Logger instead of DMA::Logger? [DMA ?-20080502]
1021             # * Add the priority field to all calls as a standard arg.
1022             # [DMA20080407-20080502]
1023             # * Move the target to the @rest arguments. [DMA20080407-20080502]
1024             # * I should check that priority contains a valid priority, that
1025             # and type is a single word. get_*_args are a great place to do it
1026             # once and for all if I can decided what to do with an wrong one.
1027             # [DMA ?-20080503]
1028             # * Expand delegate to a list to allow logging to multiple locations.
1029             # If I do, should I make initfault do an or of tables or keep
1030             # individual tables? [DMA20080407-20080503]
1031             # * Update example.pl for multiple delegates. [DMA20080503-20080504]
1032             # * replace warns with ErrorHandler calls where reasonable.
1033             # [DMA20080503-20080505]
1034             # * _delegateExists operation so I can add only if new and delete
1035             # only if it exists. Question is, what does exist mean? Stdout
1036             # should only have one instance; probably same with DB; but what
1037             # about multiple File delegates with different output files?
1038             # (Created Delegate List class. [DMA20080503-20080506]
1039             # * I should use a hash instead of a list for delegates and treat
1040             # them as handles. Stdout could be a class object if I am worried
1041             # about multiple use of it. [DMA20080503-20080506]
1042             # * Can I do anything more with commonalities in arg_check methods?
1043             # (Nothing left that is worth the effort.) [DMA20080503-20080506]
1044             # * Make sure all delegates do their arg and failure checking.
1045             # [DMA20080504-20080506]
1046             # * Should Delegate new be able to fail and return undef if a delegate
1047             # cannot be initialized? (yes) [DMA ?-20080506]
1048             # * Check all use of $s as it might be the class name in some
1049             # circumstances and I have changed the flow such that it will now
1050             # cause problems. [DMA20080506-20080607]
1051             # * Message is not being saved. (Now done in _log)
1052             # [DMA20080506-20080507]
1053             # * Carefully check all the documentation. [DMA20080506-20080507]
1054             # * When I add a new delegate, should I immediately do an initfault?
1055             # (Yes. I am putting all of this in Fault::Delegate::List
1056             # [DMA20080503-20080508]
1057             1;