File Coverage

blib/lib/File/Log.pm
Criterion Covered Total %
statement 114 186 61.2
branch 29 90 32.2
condition 11 39 28.2
subroutine 15 24 62.5
pod 13 13 100.0
total 182 352 51.7


line stmt bran cond sub pod time code
1             #
2             # Log.pm
3             #
4             # Synopsis: see POD at end of file
5             #
6             #
7             #-- The package
8             #------------------
9             package File::Log;
10              
11             $VERSION = sprintf("%d.%02d", q'$Revision: 1.5 $' =~ /(\d+)\.(\d+)/);
12             #------------------
13             #
14              
15             #-- Required Modules
16             #-------------------
17 1     1   8339 use vars qw($_errStr $_expText);
  1         2  
  1         71  
18 1     1   31 use 5.006;
  1         4  
  1         43  
19 1     1   7 use strict;
  1         14  
  1         82  
20 1     1   6 use warnings;
  1         3  
  1         60  
21 1     1   7 use Carp qw(confess);
  1         2  
  1         65  
22 1     1   1147 use Symbol;
  1         1256  
  1         93  
23 1     1   8473 use Encode;
  1         15399  
  1         431  
24              
25              
26             #-- Global Variables
27             #-------------------
28             $_errStr = '';
29             $_expText = ''; # Used to store all text sent to exp() if storeExpText flag set
30              
31              
32             # Constructor new
33             sub new
34             {
35 1     1 1 205 my $proto = shift;
36 1   33     10 my $class = ref($proto) || $proto;
37              
38 1         4 my $self = {};
39 1         4 bless($self, $class);
40              
41             # Run initialisation code
42 1         5 return $self->_init(@_);
43             }
44              
45             sub _init
46             {
47 1     1   2 my $self = shift;
48              
49             # Set some initial default values
50 1         8 $self->{'logfilemode' } = '>>';
51 1         3 $self->{'debug' } = 4;
52 1         2 $self->{'pidstamp' } = 0;
53 1         3 $self->{'datetimestamp' } = 0;
54 1         4 $self->{'stderrredirect' } = 1;
55 1         3 $self->{'defaultfile' } = 0;
56 1         3 $self->{'_logFileOpen' } = 0;
57 1         7 $self->{'_fileHandle' } = gensym;
58 1         18 $self->{'storeexptext' } = 0;
59 1         2 $self->{'logfiledatetime' } = 0;
60 1         3 $self->{'_expCnt' } = 0;
61 1         157 $self->{'encode' } = undef;
62 1         5 $self->{'stdout' } = 0;
63 1         2 $self->{'say' } = 0;
64 1         4 $self->{'msgprepend' } = '';
65 1         5 $self->{'dateFormat' } = '';
66              
67              
68              
69              
70             # Have we been passed anything
71 1 50       54 if (@_ != 0)
72             {
73             # We are expecting our configuration to come as an anonymous hash
74 0 0       0 if (ref $_[0] eq 'HASH')
75             {
76 0         0 my $hash=$_[0];
77              
78 0         0 foreach my $key (keys %$hash)
79             {
80 0         0 $self->{lc($key)}=$hash->{$key};
81             }
82             }
83             else
84             {
85             # Using a more conventional named args
86 0         0 my %args = @_;
87 0         0 foreach my $key (keys %args)
88             {
89 0         0 $self->{lc($key)}=$args{$key};
90             }
91             }
92             }
93              
94             # Do we have a name for the log file.
95             # If no Do we have the name of the application - since this will form the basis of the log file name
96 1 0 33     7 unless (defined($self->{'logfilename'}) && $self->{'logfilename'} ne '' && defined($self->{'appname'}) && $self->{'appname'} ne '')
      33        
      0        
97             {
98 1     1   1048 use FindBin qw($RealBin $RealScript);
  1         1446  
  1         4558  
99              
100             # Get the real location and name of the application and strip unwanted extensions
101 1         24 (my $appName = "$RealBin/$RealScript") =~ s/\.pl$|\.bat$|\.cmd$//i;
102              
103 1         4 $self->{'appname'} = $appName;
104              
105 1 50 33     7 $self->{'logfilename'} = $self->{'appname'}.'.log' unless (defined($self->{'logfilename'}) && $self->{'logfilename'} ne '');
106             }
107              
108             # Open the logfile
109 1         5 return $self->_open;
110             }
111              
112              
113              
114             sub _open
115             {
116 1     1   2 my $self = shift;
117              
118             # If the current log file is open close it.
119 1 50       4 close($self->{'_fileHandle'}) if($self->{'_logFileOpen'});
120              
121 1         2 my $logFileName = $self->{'logfilename'};
122 1 50       6 if ($self->{'logfiledatetime'})
123             {
124             #-- Current day & time
125 0         0 my ($tm_sec, $tm_min, $tm_hr, $tm_day, $tm_month, $tm_year, undef, undef, undef) = localtime();
126 0         0 my $file_DT = sprintf "%d%02d%02d-%02d%02d%02d", ($tm_year + 1900), ($tm_month + 1), $tm_day, $tm_hr, $tm_min, $tm_sec;
127              
128 0         0 $logFileName =~ s/(\.[^.]*?$)/"_$file_DT$1"/e;
  0         0  
129             }
130              
131             # Restore the log file name
132 1         3 $self->{'logfilename'} = $logFileName;
133              
134             # Actually open the log file
135 1         2 my $openStatus;
136 1         3 my $mode = $self->{'logfilemode'};
137 1 50 33     17 if ($] >= 5.008002 && defined $self->{'encode'} && $self->{'encode'} ne '')
      33        
138             {
139 0         0 $mode = $self->{'logfilemode'}.':'.$self->{'encode'};
140 0         0 $openStatus = open($self->{'_fileHandle'}, $mode, $logFileName)
141             }
142             else
143             {
144 1         137 $openStatus = open($self->{'_fileHandle'}, $mode.$logFileName);
145             }
146              
147 1 50       9 unless ($openStatus)
148             {
149 0         0 $_errStr = "Could not open '$logFileName' with mode '$mode': $! ";
150 0         0 $self->{'_logFileOpen'} = 0;
151 0         0 return undef;
152             }
153              
154             # Set the internal flag to indicate that the file is open
155 1         3 $self->{'_logFileOpen'} = 1;
156 1         3 $_errStr = '';
157              
158 1         5 local *LF = $self->{'_fileHandle'};
159              
160             # Do we need to redirect stderr to the logfile
161 1 50       4 if ($self->{stderrredirect})
162             {
163 1         25 close STDERR;
164 1 50       149 unless (open(STDERR, '>&LF'))
165             {
166             # There was an error, log it to the file and set the package error string
167 0         0 my ($pkg, $file, $line) = caller;
168              
169 0         0 my $err = "Error Package: $pkg, File: $file, Line: $line\n";
170 0         0 $err .= "Close and dup of STDERR to log file '$logFileName' failed: $! ";
171              
172 0         0 print {$self->{'_fileHandle'}} $err."\n";
  0         0  
173 0         0 $_errStr = $err;
174             }
175             }
176              
177             # Need to redirect STDOUT to the log file if select is used to set the default file handle
178 1 50       4 if ($self->{'defaultfile'})
179             {
180 0 0       0 unless (open(STDOUT, '>&LF'))
181             {
182             # There was an error, log it to the file and set the package error string
183 0         0 my ($pkg, $file, $line) = caller;
184              
185 0         0 my $err = "Error Package: $pkg, File: $file, Line: $line\n";
186 0         0 $err .= "Close and dup of STDOUT to log file '$logFileName' failed: $!";
187              
188 0         0 print LF $err."\n";
189 0         0 $_errStr = $err;
190             }
191             }
192              
193             # Set autoflush
194 1         5 my $oldSelect = select LF;
195 1         4 $| = 1;
196 1 50       6 select $oldSelect unless ($self->{'defaultfile'});
197              
198             # Make the log file readable by all, modifiable by the owner
199 1         59 chmod 0644, $logFileName;
200              
201 1         7 return $self;
202             }
203              
204              
205              
206             sub msg
207             {
208 2     2 1 35 my $self = shift;
209              
210 2         4 my $now = '';
211 2         3 my $pid = '';
212 2         3 my $msg_prepend = '';
213              
214             # Do we have enough parameters
215 2 50       7 @_ > 1 or confess 'Usage: log->msg(debugLevel, "message string"|@messageStrings)';
216              
217             # If the supplied debug level is greater than the current debug value return
218 2 50       8 return if shift > $self->{'debug'};
219              
220 2         5 my $str = join('', @_);
221              
222             # Set the timestamp if required
223 2 50       6 if ($self->{'datetimestamp'})
224             {
225 0 0       0 if ($self->{'dateformat'})
226             {
227 0         0 require POSIX;
228 0         0 $now = POSIX::strftime($self->{'dateformat'}, localtime) . ' ';
229             }
230             else
231             {
232 0         0 $now = scalar(localtime()) . ' ';
233             }
234             }
235              
236             # Set the process ID if required
237 2 50       425 $pid = $$ . ' ' if ($self->{'pidstamp'});
238              
239             # Prepend text if necessary
240 2 50       6 $msg_prepend = $self->{'msgprepend'} if $self->{'msgprepend'};
241              
242             # Format the string and print it to the logfile
243 2         8 $str =~ s/\n(?=.)/\n$pid$now$msg_prepend/gs;
244              
245 2 50 33     17 if ($] >= 5.008002 && defined $self->{'encode'} && $self->{'encode'} ne '')
      33        
246             {
247 0         0 $pid = encode($self->{'encode'}, $pid);
248 0         0 $now = encode($self->{'encode'}, $now);
249             }
250 2         2 print {$self->{'_fileHandle'}} $pid, $now, $msg_prepend, $str;
  2         65  
251 2 50       11 print {$self->{'_fileHandle'}} "\n" if $self->{'say'};
  0         0  
252              
253 2 50       7 print STDOUT $pid, $now, $msg_prepend, $str if $self->{'stdout'};
254 2 50       11 print STDOUT "\n" if $self->{'say'};
255             }
256              
257              
258             sub say
259             {
260 1     1 1 391 my $self = shift;
261              
262 1         4 $self->msg(@_, "\n");
263             }
264              
265              
266             sub exp
267             {
268 1     1 1 1111 my $self = shift;
269              
270 1         3 my $now = '';
271 1         2 my $pid = '';
272 1         2 my $msg_prepend = '';
273              
274             # Do we have enough parameters
275 1 50       6 @_ >= 1 or confess 'Usage: log->msg(debugLevel, "message string"|@messageStrings)';
276              
277             # Keep track of the number of exception calls for this object
278 1         446 $self->_incExpCnt;
279              
280 1         3 my $str = join('', @_);
281              
282             # Set the timestamp if required
283 1 50       7 if ($self->{'datetimestamp'})
284             {
285 0 0       0 if ($self->{'dateformat'})
286             {
287 0         0 require POSIX;
288 0         0 $now = POSIX::strftime($self->{'dateformat'}, localtime) . ' ';
289             }
290             else
291             {
292 0         0 $now = scalar(localtime()) . ' ';
293             }
294             }
295              
296             # Set the process ID if required
297 1 50       5 $pid = $$ . ' ' if ($self->{'pidstamp'});
298              
299             # Prepend text if necessary
300 1 50       5 $msg_prepend = $self->{'msgprepend'} if $self->{'msgprepend'};
301              
302             # Format the string and print it to the logfile
303 1         5 $str =~ s/\n(?=.)/\n** $pid$now$msg_prepend/gs;
304              
305 1         5 my $prefix = "** $pid$now$msg_prepend";
306 1 50 33     19 if ($] >= 5.008002 && defined $self->{'encode'} && $self->{'encode'} ne '')
      33        
307             {
308 0         0 $prefix = encode($self->{'encode'}, $prefix);
309             }
310              
311 1         6 print {$self->{'_fileHandle'}} $prefix, $str;
  1         27  
312 1 50       6 print {$self->{'_fileHandle'}} "\n" if $self->{'say'};
  0         0  
313              
314 1 50       4 print STDOUT $prefix, $str if $self->{'stdout'};
315 1 50       4 print STDOUT "\n" if $self->{'say'};
316              
317             # Append the sting if store mode is true
318 1 50       4 $_expText .= $prefix.$str if $self->{'storeexptext'};
319 1 50 33     8 $_expText .= "\n" if ($self->{'storeexptext'} && $self->{'say'});
320             }
321              
322              
323              
324             sub close
325             {
326 0     0 1 0 my $self = shift;
327              
328 0 0 0     0 close *{$self->{'_fileHandle'}} if (ref($self->{'_fileHandle'}) eq 'GLOB' && $self->{'_logFileOpen'});
  0         0  
329 0         0 $self->{'_logFileOpen'} = 0;
330             }
331              
332              
333             sub PIDstamp
334             {
335 0     0 1 0 my $self = shift;
336 0         0 my $prev = $self->{'pidstamp'};
337 0 0       0 if (@_)
338             {
339 0 0       0 $self->{'pidstamp'} = ($_[0] ? 1: 0);
340             }
341 0         0 return $prev;
342             }
343              
344              
345              
346             sub dateTimeStamp
347             {
348 0     0 1 0 my $self = shift;
349 0         0 my $prev = $self->{'datetimestamp'};
350 0 0       0 if (@_)
351             {
352 0 0       0 $self->{'datetimestamp'} = ($_[0] ? 1: 0);
353             }
354 0         0 return $prev;
355             }
356              
357              
358              
359             sub debugValue
360             {
361 0     0 1 0 my $self = shift;
362 0         0 my $prev = $self->{'debug'};
363 0 0       0 if (@_)
364             {
365             # Update the debug value if it's greater than zero
366 0 0       0 $self->{'debug'} = int($_[0]) if ($_[0] >= 0);
367             }
368 0         0 return $prev;
369             }
370              
371              
372              
373             sub expText
374             {
375 0     0 1 0 my $self = shift;
376 0         0 my $prev = $self->{'storeexptext'};
377 0 0       0 if (@_)
378             {
379             # Update the storeexptext value
380 0         0 $self->{'storeexptext'} = $_[0];
381             }
382 0         0 return $prev;
383             }
384              
385              
386              
387             sub getExpText
388             {
389 0     0 1 0 my $self = shift;
390              
391             # Return undef if we don't have storeExpText flag set
392 0 0       0 return(wantarray ? () : undef) unless $self->{'storeexptext'};
    0          
393              
394 0 0       0 return(wantarray ? ($_expText) : $_expText);
395             }
396              
397              
398              
399             sub clearExpText
400             {
401 0     0 1 0 my $self = shift;
402              
403 0         0 $_expText = '';
404             }
405              
406 0     0 1 0 sub expCnt { return $_[0]->{_expCnt}; }
407 1     1   10 sub _incExpCnt { $_[0]->{_expCnt}++; }
408 0     0 1   sub getLogFileName { return $_[0]->{'logfilename'}; }
409              
410              
411             #####################################################################
412             # DO NOT REMOVE THE FOLLOWING LINE, IT IS NEEDED TO LOAD THIS LIBRARY
413             1;
414              
415              
416             __END__
417              
418             ## POD DOCUMENTATION ##
419              
420              
421             =head1 NAME
422              
423             File::Log - A simple Object Orientated Logger
424              
425             =head1 SYNOPSIS
426              
427             use File::Log;
428              
429             # Pretty format, all the parameters
430             my $log = File::Log->new({
431             debug => 4, # Set the debug level
432             logFileName => 'myLogFile.log', # define the log filename
433             logFileMode => '>', # '>>' Append or '>' overwrite
434             dateTimeStamp => 1, # Timestamp log data entries
435             stderrRedirect => 1, # Redirect STDERR to the log file
436             defaultFile => 1, # Use the log file as the default filehandle
437             logFileDateTime => 1, # Timestamp the log filename
438             appName => 'myApplicationName', # The name of the application
439             PIDstamp => 1, # Stamp the log data with the Process ID
440             storeExpText => 1, # Store internally all exp text
441             msgprepend => '', # Text to prepend to each message
442             say => 1, # msg() and exp() methode act like the perl6 say
443             # command (default off) requested by Aaleem Jiwa
444             # however it might be better to just use the say()
445             # method
446             });
447              
448             # Minimal instance, logfile name based on application name
449             my $log = File::Log->new();
450              
451             # Typical usage, set the debug level and log filename (say from a config file)
452             my $log = File::Log->new(debug => $debugLevel, logFileName => $logFileName,);
453              
454             # Print message to the log file if the debug is >= 2
455             $log->msg(2, "Add this to the log file if debug >= 2\n");
456              
457             # Print message to the log file if the debug is >= 2 (but in a perl6 way)
458             $log->say(2, "Add this to the log file if debug >= 2");
459              
460             # Print an exception (error) message to the log file
461             $log->exp("Something went wrong\n");
462              
463             # Close the log file (optional at exit)
464             $log->close();
465              
466             # Change the debug level, capturing the old value
467             $oldDebugValue = $log->debugValue($newDebugValue);
468              
469             $currentDebugValue = $log->debugValue();
470              
471             # Get all the exceptions text (so you can do something with all the errors, eg email them)
472             $allExceptions = $log->getExpText();
473              
474             $numberErrors = $log->expCnt(); # How many times has $log->exp been called
475              
476             =head1 DESCRIPTION
477              
478             I<File::Log> is a class providing methods to log data to a file. There are a number
479             of parameters that can be passed to allow configuration of the logger.
480              
481             =head1 REQUIRED MODULES
482              
483             Carp (confess is used), FindBin and Symbol;
484              
485             =head1 METHODS
486              
487             There are no class methods, the object methods are described below.
488             Private class method start with the underscore character '_' and
489             should be treated as I<Private>.
490              
491             =head2 new
492              
493             Called to create a I<File::Log> object. The following optional named parameters can be
494             passed to the constructor via an anonymous hash:
495              
496             =over 4
497              
498             =item debug
499              
500             Used to set the debug level. The default level is 9. The debug level is used by
501             other methods to determine if data is logged or ignored. See C<msg> and C<exp> methods.
502              
503             =item logFileName
504              
505             Defines the path and name of the log file that is written too. If not defined then
506             the value of appName with '.log' appended is used. If appName is not defined in the
507             constructor then BinFind is used to determine the name of the application.
508              
509             =item logFileMode
510              
511             Used to determine if the log file is overwritten or appended too.
512             Default is append. Valid value are '>' for overwrite and '>>' for append.
513              
514             =item dateTimeStamp
515              
516             If true (default is false), then each entry written to the log file using the C<msg> and
517             C<exp> methods has the current date and time prepended to the data.
518              
519             =item stderrRedirect
520              
521             If true (default is true), then redirect STDERR to the log file.
522              
523             =item defaultFile
524              
525             If true (default is false), then select the log file as the default output file.
526              
527             =item logFileDateTime
528              
529             If true (default is false), then include the date and time into the name of the log file
530             just before the '.log'. The format of the date and time used is _YYYYMMDD-HHMMSS
531              
532             =item appName
533              
534             If logFileName is not defined then the appName is used as the basis of the log file.
535             If appName is not defined then the FindBin module is use to determine the name of the
536             application and is stored within the appName hash variable.
537              
538             =item PIDstamp
539              
540             If true (default is false), then the Process ID is prepended to the data written to the log file
541             by the C<msg> and C<exp> methods. This is handy when there are more than one processes writting
542             to the same log file.
543              
544             =item storeExpText
545              
546             If true (default is false), then any data written with the C<exp> method is also stored internally for
547             later retrival with the C<getExpText> method. The stored data can also be cleared with the C<clearExpText>
548             method. This can be useful if there may be multiple exceptions which you then want to report on (other
549             than in the log file) as one text string.
550              
551             =item msgprepend
552              
553             If anything (default is nothing), prepends its value to the end of each message passed to msg()/exp()/say() methods.
554              
555             =item dateFormat
556              
557             If defined, holds the strftime-compatible format for dateTimeStamp.
558              
559             =item say
560              
561             If true (default false) causes msg() and exp() methods to append a newline character to the end of the passed
562             message. A (possibly) B<better> approach is to just use the say() method rather then msg().
563              
564             =back
565              
566              
567             =head2 _init & Private methods
568              
569             I<Private> method to initialise the object on construction. Called by C<new()>.
570             All I<Private> methods start with B<_> and should be treated as PRIVATE. No other
571             private methods are documented (since they are private).
572              
573             =head2 msg
574              
575             The C<msg> method is used to log a message to the log file. The first B<POSITIONAL> argument
576             to C<msg> is the "debug level" at which the message should be added to the log file if the instance
577             "debug value" is greater than or equal to the "debug level".
578              
579             The second and optional subsiquent arguments are treated as text to print to the log file.
580              
581             eg. $log->msg(2, "Printed to log file if 'debug' is greater than or equal to 2 \n");
582              
583             B<Note> that newline characters are B<not> automatically appended by this method.
584              
585             =head2 say
586              
587             Same as msg except a newline '\n' is appended to the end of the line
588              
589             =head2 exp
590              
591             C<exp> is used to report exceptions. There is no "debug level" parameter,
592             just one or more text strings which are printed to the log file. The text printed
593             has "**" prepended to each line (this occurs before prepended timestamp or PID values).
594              
595             B<Note> that newline characters are B<not> automatically appended by this method.
596              
597             =head2 close
598              
599             Closes the file handle associated with the log file.
600              
601             =head2 DESTROY
602              
603             C<DESTROY> is defined and closes the file handle associated with the log file.
604              
605              
606             =head2 PIDstamp
607              
608             The C<PIDstamp> method can be used to set or get the value of the I<PIDstamp> instance variable.
609             If called without parameters, the current value of the I<PIDstamp> instance variable is returned.
610             If called with a parameter, the parameter is used to set the I<PIDstamp> instance variable and the
611             previous value is returned.
612              
613             Refer to the C<new> method for further information.
614              
615             =head2 dateTimeStamp
616              
617             The C<dateTimeStamp> method can be used to set or get the value of the I<dateTimeStamp> instance variable.
618             If called without parameters, the current value of the I<dateTimeStamp> instance variable is returned.
619             If called with a parameter, the parameter is used to set the I<dateTimeStamp> instance variable and the
620             previous value is returned.
621              
622             Refer to the C<new> method for further information.
623              
624              
625             =head2 debugValue
626              
627             The C<debugValue> method can be used to set or get the value of the I<debugValue> instance variable.
628             If called without parameters, the current value of the I<debugValue> instance variable is returned.
629             If called with a parameter, the parameter is used to set the I<debugValue> instance variable and the
630             previous value is returned.
631              
632             Refer to the C<new> method for further information.
633              
634             =head2 expText
635              
636             The C<expText> method can be used to set or get the value of the I<storeexptext> instance variable.
637             If called without parameters, the current value of the I<storeexptext> instance variable is returned.
638             If called with a parameter, the parameter is used to set the I<storeexptext> instance variable and the
639             previous value is returned.
640              
641             Refer to the C<new> method for further information.
642              
643             =head2 getExpText
644              
645             The C<expText> method is used to retreive the stored value of the instance "Exception Text".
646              
647             =head2 clearExpText
648              
649             The C<clearExpText> method is used to clear the stored value of the instance "Exception Text".
650              
651             =head2 expCnt
652              
653             The C<expCnt> method is used to retreive the number of times that the exp method has been called for this object.
654              
655             =head2 getLogFileName
656              
657             The C<getLogFileName> method is used to retreive the actual log file name used for this object.
658              
659             =head1 PROPERTIES
660              
661             see the C<new> method.
662              
663             =head1 KNOWN ISSUES
664              
665             None, however please contact the author at gng@cpan.org should you
666             find any problems and I will endevour to resolve then as soon as
667             possible.
668              
669             If you have any enhancement suggestions please send me
670             an email and I will try to accommodate your suggestion.
671              
672             Setting 'say' to true in the new() method and then using
673             the say() method will give you two newlines.
674              
675             =head1 ENHANCEMENT REQUEST/BUGS
676              
677             Thanks to the following for enhancement suggestions or bug reports:
678              
679             Aaleem Jiwa - say() method
680             Paul K - msgprepend and dateformat
681              
682             =head1 AUTHOR
683              
684             Greg George, IT Technology Solutions P/L, Australia
685             Mobile: +61-404-892-159, Email: gng@cpan.org
686              
687             =head1 LICENSE
688              
689             Copyright (c) 1999- Greg George. All rights reserved. This
690             program is free software; you can redistribute it and/or modify it under
691             the same terms as Perl itself.
692              
693             =head1 CVS ID
694              
695             $Id: Log.pm,v 1.5 2008/03/01 02:56:01 Greg Exp $
696              
697             =head1 CHANGE HISTORY
698              
699             $Log: Log.pm,v $
700             Revision 1.5 2008/03/01 02:56:01 Greg
701             - Updated Makefile.PL to include prereq for Encode as I was getting cpan tester errors. NO CODE CHANGES
702              
703              
704             Revision 1.4 2008/02/26 08:54:31 Greg
705             - Updated POD
706              
707             Revision 1.3 2007/07/17 11:23:49 Greg
708             - Added say() method
709             - Added say, msgprepend and dateFormat arguments to new()
710             - Added pre close of STDERR
711              
712             Revision 1.2 2004/10/08 23:10:14 Greg
713             - Changed new() to allow named argument as well as the anonymous hash reference.
714              
715             Revision 1.1.1.1 2004/07/29 11:15:06 Greg
716             - Initial release to CPAN
717              
718             =cut
719              
720              
721             #---< End of File >---#