File Coverage

blib/lib/Hardware/UPS/Perl/Logging.pm
Criterion Covered Total %
statement 107 503 21.2
branch 8 176 4.5
condition 0 36 0.0
subroutine 27 67 40.3
pod 18 18 100.0
total 160 800 20.0


line stmt bran cond sub pod time code
1             package Hardware::UPS::Perl::Logging;
2              
3             #==============================================================================
4             # package description:
5             #==============================================================================
6             # This package supplies a set of methods to log messages to a file. For a
7             # detailed description see the pod documentation included at the end of this
8             # file.
9             #
10             # List of public methods:
11             # -----------------------
12             # new - initializing a Hardware::UPS::Perl logging object
13             # getErrorMessage - getting internal error messages
14             # getHandle - getting the filehandle of the current log file
15             # getLogFile - getting the current log file
16             # getRotationPeriod - getting the current period used for rotating
17             # log files
18             # getRotationScheme - getting the current scheme used for rotating
19             # log files
20             # getRotationSize - getting the current size used for rotating
21             # log files
22             # rotate - forces rotation of the log file
23             # debug - printing debug messages to log file
24             # info - printing normal messages to log file
25             # error - printing error messages to log file
26             # fatal - printing fatal error messages to log file and die
27             # print - printing any message to the log file
28             # write - printing a formatted message to the log file
29             # syslog - printing message to syslog
30             # setMailTo - setting the current mail recipient
31             # getMailTo - getting the current mail recipient
32             # sendmail - sending email
33             #
34             #==============================================================================
35              
36             #==============================================================================
37             # Copyright:
38             #==============================================================================
39             # Copyright (c) 2007 Christian Reile, . All
40             # rights reserved. This program is free software; you can redistribute it
41             # and/or modify it under the same terms as Perl itself.
42             #==============================================================================
43              
44             #==============================================================================
45             # Entries for Revision Control:
46             #==============================================================================
47             # Revision : $Revision: 1.9 $
48             # Author : $Author: creile $
49             # Last Modified On: $Date: 2007/04/14 09:37:26 $
50             # Status : $State: Exp $
51             #------------------------------------------------------------------------------
52             # Modifications :
53             #------------------------------------------------------------------------------
54             #
55             # $Log: Logging.pm,v $
56             # Revision 1.9 2007/04/14 09:37:26 creile
57             # documentation update.
58             #
59             # Revision 1.8 2007/04/07 15:16:38 creile
60             # adaptations to "best practices" style;
61             # update of documentation.
62             #
63             # Revision 1.7 2007/03/13 17:21:20 creile
64             # usage of Perl pragma constant for some package variables;
65             # options as anonymous hashes;
66             # method write() revised.
67             #
68             # Revision 1.6 2007/03/03 21:18:32 creile
69             # new variable $UPSERROR added;
70             # adaptations to revised Constants.pm;
71             # "return undef" replaced by "return";
72             # new method write() for formatted output added.
73             #
74             # Revision 1.5 2007/02/25 17:07:14 creile
75             # option handling redesigned.
76             #
77             # Revision 1.4 2007/02/05 20:34:31 creile
78             # bug fix creating symlink of log file;
79             # pod documentation revised.
80             #
81             # Revision 1.3 2007/02/04 14:03:50 creile
82             # bug fix in pod documentation.
83             #
84             # Revision 1.2 2007/02/03 20:49:23 creile
85             # support for syslog and sending mail added;
86             # different rotation schemes introduced (naone, daily, period
87             # and size);
88             # private methods _rotate() and _setLogFile() revised;
89             # log file is truncated now, if it already exists;
90             # update of documentation.
91             #
92             # Revision 1.1 2007/01/30 23:03:19 creile
93             # initial revision.
94             #
95             #
96             #==============================================================================
97              
98             #==============================================================================
99             # module preamble:
100             #==============================================================================
101              
102 1     1   6 use strict;
  1         2  
  1         46  
103              
104             BEGIN {
105            
106 1     1   6 use vars qw($VERSION @ISA);
  1         2  
  1         97  
107              
108 1     1   10 $VERSION = sprintf( "%d.%02d", q$Revision: 1.9 $ =~ /(\d+)\.(\d+)/ );
109              
110 1         40 @ISA = qw();
111              
112             }
113              
114             #==============================================================================
115             # end of module preamble
116             #==============================================================================
117              
118             #==============================================================================
119             # packages required:
120             #------------------------------------------------------------------------------
121             #
122             # Carp - warn of errors (from perspective of
123             # caller)
124             # constant - Perl pragma to declare constants
125             # Date::Format - Date formating subroutines
126             # Fcntl - load the C Fcntl.h defines
127             # File::Basename - parse file paths into directory, filename
128             # and suffix
129             # File::Find - traverse a directory tree
130             # FileHandle - supply object methods for filehandles
131             # Mail::Send - simple electronic mail interface
132             # Sys::Syslog - Perl interface to the UNIX syslog(3)
133             # calls
134             # Time::HiRes - high resolution alarm, sleep,
135             # gettimeofday, interval timers
136             #
137             # Hardware::UPS::Perl::Constants - importing Hardware::UPS::Perl constants
138             # Hardware::UPS::Perl::General - importing Hardware::UPS::Perl variables
139             # and functions for scripts
140             # Hardware::UPS::Perl::Utils - importing Hardware::UPS::Perl utility
141             # functions for packages
142             #
143             #==============================================================================
144              
145 1     1   6 use Carp;
  1         2  
  1         74  
146 1     1   1211 use Date::Format;
  1         11004  
  1         91  
147 1     1   13 use Fcntl;
  1         1  
  1         424  
148 1     1   9 use File::Basename;
  1         2  
  1         81  
149 1     1   7 use File::Find;
  1         3  
  1         65  
150 1     1   1325 use FileHandle;
  1         14657  
  1         8  
151 1     1   1726 use Mail::Send;
  1         4628  
  1         42  
152 1     1   1169 use Sys::Syslog ();
  1         10506  
  1         42  
153              
154 1         8 use Time::HiRes qw(
155             time
156             setitimer
157             ITIMER_REAL
158 1     1   1085 );
  1         2170  
159              
160 1         81 use Hardware::UPS::Perl::Constants qw(
161             UPSHOSTNAME
162             UPSMAILTO
163             UPSSCRIPT
164 1     1   280 );
  1         3  
165 1         117 use Hardware::UPS::Perl::General qw(
166             $UPSERROR
167 1     1   10 );
  1         3  
168 1         100 use Hardware::UPS::Perl::Utils qw(
169 1     1   793 );
  1         3  
170              
171             #==============================================================================
172             # defining user invisible package variables and constants:
173             #------------------------------------------------------------------------------
174             #
175             # %ROTATION_SCHEME - the table of rotation schemes
176             # ROTATION_PERIOD - the default period to rotate log files
177             # in seconds
178             # ROTATION_SIZE - the default size to rotate log files in
179             # bytes
180             # ALARM_PERIOD - the period to trigger the alarm signal
181             # in seconds
182             #
183             #==============================================================================
184              
185             my %ROTATION_SCHEME = (
186             none => 0,
187             daily => 1,
188             period => 2,
189             size => 3,
190             );
191              
192 1     1   7 use constant ROTATION_PERIOD => 60 * 60 * 24;
  1         3  
  1         83  
193 1     1   7 use constant ROTATION_SIZE => 1024 * 1024;
  1         2  
  1         54  
194 1     1   6 use constant ALARM_PERIOD => 60;
  1         2  
  1         2554  
195              
196             #==============================================================================
197             # public methods:
198             #==============================================================================
199              
200             sub new {
201              
202             # public method to construct a logging object
203             #
204             # parameters: $class (input) - class
205             # $options (input) - anonymous hash; options
206             #
207             # The following option keys are recognized:
208             #
209             # File ($) - the log file; optional;
210             # MailTo ($) - the mail recipient; optional; default: UPSMAILTO
211             # Period ($) - the rotation period in minutes,
212             # implies Scheme = "period"; optional;
213             # default: ROTATION_PERIOD
214             # Scheme ($) - the rotation scheme:
215             # Scheme = "none" : no rotation (default);
216             # "daily" : rotation on a daily basis;
217             # "period": periodically rotation;
218             # "size" : rotation based on size;
219             # optional;
220             # Size ($) - the rotation size in megabytes, implies Scheme = "size";
221             # optional; default: ROTATION_SIZE.
222              
223             # input as hidden local variables
224 1     1 1 17 my $class = shift;
225 1 50       15 my $options = @_ ? shift : {};
226              
227             # hidden local variables
228 1         2 my $self = {}; # referent to be blessed
229 1         3 my $refType; # the reference type
230             my %processOption; # the action table to process options
231 0         0 my $option; # an option
232 0         0 my $arg; # an option argument
233 0         0 my $logFile; # the name of the log file
234 0         0 my $mailTo; # the mail recipient
235 0         0 my $scheme; # the rotation scheme
236 0         0 my $period; # the rotation period
237 0         0 my $size; # the rotation size
238              
239             # blessing logging object
240 1         3 bless $self, $class;
241              
242             # checking options
243 1         3 $refType = ref($options);
244 1 50       4 if ($refType ne 'HASH') {
245 0         0 error("not a hash reference -- <$refType>");
246             }
247              
248             # processing options, starting with defaults
249 1         2 $mailTo = UPSMAILTO;
250 1         2 $period = ROTATION_PERIOD;
251 1         2 $scheme = "none";
252 1         2 $size = ROTATION_SIZE;
253              
254             %processOption = (
255             File => sub { # the name of the log file
256 0     0   0 $logFile = shift;
257             },
258             MailTo => sub { # the mail recipient
259 0     0   0 $mailTo = shift;
260             },
261             Period => sub { # the rotating period in minutes
262 0     0   0 my $arg = shift;
263            
264 0 0       0 if (exists $options->{Size}) {
265 0         0 Hardware::UPS::Perl::Utils::error(
266             "unexpected option -- Period"
267             );
268             }
269              
270 0 0 0     0 if ($arg =~ /\d+/ and ($arg > 0)) {
271 0         0 $period = $arg * 60;
272             }
273             else {
274 0         0 Hardware::UPS::Perl::Utils::error(
275             "not a natural number -- $arg"
276             );
277             }
278              
279 0 0       0 if (!exists $options->{Scheme}) {
280 0         0 $scheme = "period"
281             }
282              
283             },
284             Scheme => sub { # the rotation scheme: none, daily, period, size
285 0     0   0 my $arg = shift;
286              
287 0 0       0 if (exists $ROTATION_SCHEME{$arg}) {
288 0         0 $scheme = $arg;
289             }
290             else {
291 0         0 Hardware::UPS::Perl::Utils::error(
292             "unknown rotation scheme -- $arg"
293             );
294             }
295              
296             },
297             Size => sub { # the rotating size in megabytes
298 0     0   0 my $arg = shift;
299              
300 0 0       0 if ( exists $options->{Period}) {
301 0         0 Hardware::UPS::Perl::Utils::error(
302             "unexpected option -- Size"
303             );
304             }
305              
306 0 0 0     0 if ($arg =~ /\d+/ and ($arg > 0)) {
307 0         0 $size = $arg * ROTATION_SIZE;
308             }
309             else {
310 0         0 Hardware::UPS::Perl::Utils::error(
311             "not a natural number -- $arg"
312             );
313             }
314            
315 0 0       0 if (!exists $options->{Scheme}) {
316 0         0 $scheme = "size";
317             }
318             },
319 1         19 );
320              
321 1         2 while (($option, $arg) = each %{$options}) {
  1         7  
322 0 0       0 if (exists $processOption{$option}) {
323 0         0 $processOption{$option}->($arg);
324             }
325             else {
326             # default: option unknown
327 0         0 Hardware::UPS::Perl::Utils::error("option unknown -- $option");
328             }
329             }
330              
331             # initializing
332 1         7 $self->{errorMessage} = q{};
333 1         6 $self->setMailTo($mailTo);
334              
335 1 50       8 if (defined $logFile) {
336              
337 0 0       0 if (ref($logFile) eq 'GLOB') {
338              
339             # we have a GLOB to pass all output to
340 0         0 $self->{_fileBase} = undef;
341              
342 0         0 $self->_setRotationScheme("none");
343 0         0 $self->_setLogFile();
344              
345 0         0 $self->{handle} = $logFile;
346              
347             }
348             else {
349              
350             # we have a real log file
351 0         0 $self->{_fileBase} = $logFile;
352              
353 0         0 $self->_setRotationPeriod($period);
354 0         0 $self->_setRotationScheme($scheme);
355 0         0 $self->_setRotationSize($size);
356              
357 0         0 $self->_setLogFile(time);
358              
359             # opening file
360             $self->_open($self->getLogFile())
361 0 0       0 or do {
362 0         0 $UPSERROR = $self->getErrorMessage();
363 0         0 return;
364             };
365              
366             # setting up timer for rotation and starting it, if we have
367             # rotation enabled
368 0 0       0 if ($ROTATION_SCHEME{$scheme}) {
369              
370 0 0       0 if ($scheme eq "period") {
371 0         0 $self->{_alarmPeriod} = $period;
372             }
373             else {
374 0         0 $self->{_alarmPeriod} = ALARM_PERIOD;
375             }
376              
377             $SIG{ALRM} = sub {
378             # rotate
379 0     0   0 $self->_rotate();
380             # setting up the alarm again
381 0         0 setitimer(ITIMER_REAL, $self->{_alarmPeriod});
382 0         0 };
383              
384 0         0 setitimer(ITIMER_REAL, $self->{_alarmPeriod});
385              
386             }
387              
388             }
389              
390             }
391             else {
392              
393             # no log file supplied, passing all output to STDERR
394 1         3 $self->{_fileBase} = undef;
395              
396 1         4 $self->_setRotationScheme("none");
397 1         5 $self->_setLogFile();
398              
399 1         2 $self->{handle} = \*STDERR;
400              
401             }
402              
403             # returning blessed logging object
404 1         19 return $self;
405              
406             } # end of public method "new"
407              
408             sub DESTROY {
409              
410             # the destructor will close the current log file
411             #
412             # parameters: $self (input) - referent to a logging object
413              
414             # input as hidden local variable
415 0     0   0 my $self = shift;
416              
417             # closing log file
418 0         0 $self->_close();
419              
420             } # end of the destructor
421              
422             sub getErrorMessage {
423              
424             # public method to get the current error message
425             #
426             # parameters: $self (input) - referent to a logging object
427              
428             # input as hidden local variable
429 0     0 1 0 my $self = shift;
430              
431             # getting the error message
432 0 0       0 if (exists $self->{errorMessage}) {
433 0         0 return $self->{errorMessage};
434             } else {
435 0         0 return;
436             }
437              
438             } # end of public method "getErrorMessage"
439              
440             sub getHandle {
441              
442             # public method to get the current log file handle
443             #
444             # parameters: $self (input) - referent to a logging object
445              
446             # input as hidden local variable
447 0     0 1 0 my $self = shift;
448              
449             # getting handle
450 0 0       0 if (exists $self->{handle}) {
451 0         0 return $self->{handle};
452             } else {
453 0         0 return;
454             }
455              
456             } # end of public method "getHandle"
457              
458             sub getLogFile {
459              
460             # public method to get the current log file
461             #
462             # parameters: $self (input) - referent to a logging object
463              
464             # input as hidden local variable
465 1     1 1 3 my $self = shift;
466              
467             # getting log file
468 1 50       3 if (exists $self->{logfile}) {
469 0         0 return $self->{logfile};
470             } else {
471 1         2 return;
472             }
473              
474             } # end of public method "getLogFile"
475              
476             sub getRotationPeriod {
477              
478             # public method to get the current rotation period
479             #
480             # parameters: $self (input) - referent to a logging object
481              
482             # input as hidden local variable
483 0     0 1 0 my $self = shift;
484              
485             # getting rotation period
486 0 0 0     0 if (exists $self->{period} and defined $self->{period}) {
487 0         0 return $self->{period} / 60;
488             } else {
489 0         0 return;
490             }
491              
492             } # end of public method "getRotationPeriod"
493              
494             sub getRotationSize {
495              
496             # public method to get the current rotation size in megabytes
497             #
498             # parameters: $self (input) - referent to a logging object
499              
500             # input as hidden local variable
501 0     0 1 0 my $self = shift;
502              
503             # getting rotation size
504 0 0 0     0 if (exists $self->{size} and defined $self->{size}) {
505 0         0 return $self->{size} / ROTATION_SIZE;
506             } else {
507 0         0 return;
508             }
509              
510             } # end of public method "getRotationSize"
511              
512             sub getRotationScheme {
513              
514             # public method to get the current rotation scheme
515             #
516             # parameters: $self (input) - referent to a logging object
517              
518             # input as hidden local variable
519 1     1 1 2 my $self = shift;
520              
521             # getting rotation scheme
522 1 50       3 if (exists $self->{scheme}) {
523 0         0 return $self->{scheme};
524             } else {
525 1         2 return;
526             }
527              
528             } # end of public method "getRotationScheme"
529              
530             sub debug {
531              
532             # public method to write debug messages to the log file
533             #
534             # parameters: $self (input) - referent to a logging object
535             # $message (input) - debug message
536              
537             # input as hidden local variable
538 0     0 1 0 my $self = shift;
539 0         0 my $message = shift;
540              
541             # printing debug message to log file
542 0         0 return $self->print("DEBUG: $message\n");
543              
544             } # end of public method "debug"
545              
546             sub info {
547              
548             # public method to write normal messages to the log file
549             #
550             # parameters: $self (input) - referent to a logging object
551             # $message (input) - normal log message
552              
553             # input as hidden local variable
554 0     0 1 0 my $self = shift;
555 0         0 my $message = shift;
556              
557             # writing info message to log file
558 0         0 return $self->print("INFO : $message\n");
559              
560             } # end of public method "info"
561              
562             sub error {
563              
564             # public method to write non-fatal error messages to the log file
565             #
566             # parameters: $self (input) - referent to a logging object
567             # $message (input) - error message
568              
569             # input as hidden local variable
570 0     0 1 0 my $self = shift;
571 0         0 my $message = shift;
572              
573             # printing error message to log file
574 0         0 return $self->print("ERROR: $message\n");
575              
576             } # end of public method "error"
577              
578             sub fatal {
579              
580             # public method to write an error messages to the log file and dieing
581             #
582             # parameters: $self (input) - referent to a logging object
583             # $message (input) - fatal error message
584              
585             # input as hidden local variable
586 0     0 1 0 my $self = shift;
587 0         0 my $message = shift;
588              
589             # printing fatal error message to log file
590 0         0 $self->print("FATAL: $message\n");
591              
592             # time to say good-bye ...
593 0         0 croak("FATAL: $message");
594              
595             } # end of public method "fatal"
596              
597             sub print {
598              
599             # public method to print messages to the log file
600             #
601             # parameters: $self (input) - referent to a logging object
602             # $message (input) - the log message
603              
604             # input as hidden local variable
605 0     0 1 0 my $self = shift;
606 0         0 my $message = shift;
607              
608             # hidden local variables
609 0         0 my $scheme; # the numerical rotation scheme
610             my $date; # the current date
611 0         0 my $alarm; # time left of the alarm
612              
613             # getting the rotation scheme
614 0         0 $scheme = $self->getRotationScheme();
615 0 0       0 if (defined $scheme) {
616 0         0 $scheme = $ROTATION_SCHEME{$scheme};
617             } else {
618 0         0 $scheme = 0;
619             }
620              
621             # writing log message
622 0         0 my $fh = $self->getHandle();
623              
624 0 0 0     0 if (defined $fh and (ref($fh) eq 'FileHandle') or (ref($fh) eq 'GLOB')) {
      0        
625              
626             # getting date
627 0         0 $date = time2str("%b %d %T", time);
628              
629             # blocking rotation
630 0 0       0 if ($scheme) {
631 0         0 $alarm = setitimer(ITIMER_REAL, 0);
632 0 0       0 if (!$alarm) {
633 0         0 $alarm = $self->{_alarmPeriod};
634             }
635             }
636              
637             # writing message to log file
638 0         0 $fh->print("$date: ".UPSSCRIPT.": $message");
639              
640             # unblocking rotation
641 0 0       0 if ($scheme) {
642 0         0 setitimer(ITIMER_REAL, $alarm);
643             }
644              
645 0         0 return 1;
646              
647             } else {
648              
649 0         0 $self->{errorMessage} = "log file unavailable";
650 0         0 return 0;
651              
652             }
653              
654             } # end of public method "print"
655              
656             sub write {
657              
658             # public method to write formatted messages to the log file
659             #
660             # parameters: $self (input) - referent to a logging object
661             # $options (input) - anonymous hash; options
662             #
663             # The following option keys are recognized:
664             #
665             # Format ($) - string; the format to use
666             # Type ($) - string; the information type;
667             # type = debug: prepending "DEBUG:";
668             # info : prepending "INFO :";
669             # this is the default;
670             # error: prepending "ERROR:";
671             # fatal: prepending "FATAL:";
672             # Arguments (%) - hash reference; the arguments used in the format
673              
674             # input as hidden local variables
675 0     0 1 0 my $self = shift;
676 0 0       0 my $options = @_ ? shift : {};
677              
678             # hidden local variables
679 0         0 my $refType; # a reference type
680             my $formatString; # the format
681 0         0 my $declaration; # the declaration part of the format
682 0         0 my @formatList; # the form list
683 0         0 my $formatName; # the name of the format
684 0         0 my $arguments = {}; # the arguments of the format
685 0         0 my $type; # the output type
686             my %processType; # action table to process the type
687 0         0 my $fatalFlag; # the flag indicating a fatal error
688 0         0 my $scheme; # the numerical rotation scheme
689 0         0 my $logDate; # the current date
690 0         0 my $alarm; # time left of the alarm
691              
692             # checking options
693 0         0 $refType = ref($options);
694 0 0       0 if ($refType ne 'HASH') {
695 0         0 Hardware::UPS::Perl::Utils::error("not a hash reference -- <$refType>");
696             }
697              
698             # format
699 0         0 $formatString = delete $options->{Format};
700              
701 0 0       0 if (!defined $formatString) {
702 0         0 Hardware::UPS::Perl::Utils::error("no format available");
703             }
704              
705             # setting up the actio table to process the type
706             %processType = (
707 0     0   0 debug => sub { $type = uc($type) ; $fatalFlag = 0; },
  0         0  
708 0     0   0 error => sub { $type = uc($type) ; $fatalFlag = 0; },
  0         0  
709 0     0   0 fatal => sub { $type = uc($type) ; $fatalFlag = 1; },
  0         0  
710 0     0   0 info => sub { $type = uc($type).q{ }; $fatalFlag = 0; },
  0         0  
711 0     0   0 none => sub { $type = q{} ; $fatalFlag = 0; },
  0         0  
712 0         0 );
713              
714             # the type
715 0         0 $type = delete $options->{Type};
716              
717 0 0       0 if (defined $type) {
718 0 0       0 if (exists $processType{ lc($type) }) {
719 0         0 $processType{ lc($type) }->();
720             }
721             else {
722             # default: type unknown
723 0         0 Hardware::UPS::Perl::Utils::error("unexpected type -- $type")
724             }
725             }
726             else {
727 0         0 $type = "INFO ";
728 0         0 $fatalFlag = 0;
729             }
730              
731              
732             # the arguments
733 0         0 $arguments = delete $options->{Arguments};
734              
735 0 0       0 if (!defined $arguments) {
736 0         0 Hardware::UPS::Perl::Utils::error("no arguments available");
737             }
738              
739             # getting the rotation scheme
740 0         0 $scheme = $self->getRotationScheme();
741 0 0       0 if (defined $scheme) {
742 0         0 $scheme = $ROTATION_SCHEME{$scheme};
743             } else {
744 0         0 $scheme = 0;
745             }
746              
747             # writing log message
748 0         0 my $fh = $self->getHandle();
749              
750 0 0 0     0 if (defined $fh and (ref($fh) eq 'FileHandle') or (ref($fh) eq 'GLOB')) {
      0        
751              
752 0 0       0 if ($type) {
753              
754             # getting date
755 0         0 $logDate = time2str("%b %d %T", time);
756              
757             # prepending logging date and scriptname to format
758 0         0 @formatList = split(/\n/, $formatString);
759 0         0 $declaration = shift(@formatList);
760 0         0 pop(@formatList);
761              
762 0         0 foreach my $line (@formatList) {
763 0 0       0 if ($line !~ m{^(\s*)\$}xms) {
764 0         0 $line = $logDate.q{: }.UPSSCRIPT.q{: }.$type.q{: }.$line;
765             }
766             }
767              
768 0         0 unshift(@formatList, $declaration);
769 0         0 push (@formatList, q{.});
770              
771 0         0 $formatString = join("\n", @formatList);
772              
773             }
774             else {
775              
776             # no prepending
777 0         0 @formatList = split(/\n/, $formatString);
778 0         0 $declaration = shift(@formatList);
779              
780             }
781              
782             # the format name
783 0         0 $formatName = (split(/\s+/, $declaration))[1];
784              
785             # evaluating format
786             {
787 1     1   9 no strict;
  1         4  
  1         46  
  0         0  
788 1     1   6 no warnings 'redefine';
  1         2  
  1         3245  
789              
790 0         0 EVAL_FORMAT:
791 0         0 while (($var, $value) = each %{$arguments}) {
792 0         0 $$var = $value;
793             }
794              
795 0         0 eval $formatString;
796 0 0       0 if ($@) {
797 0         0 $self->{errorMessage} = "format evaluation failed -- $@";
798 0         0 return 0;
799             }
800             }
801              
802             # blocking rotation
803 0 0       0 if ($scheme) {
804 0         0 $alarm = setitimer(ITIMER_REAL, 0);
805 0 0       0 if (!$alarm) {
806 0         0 $alarm = $self->{_alarmPeriod};
807             }
808             }
809              
810             # writing message to log file
811 0         0 my $oldFH = select($fh);
812 0         0 $~ = $formatName;
813 0         0 write;
814 0         0 select($oldFH);
815              
816             # unblocking rotation
817 0 0       0 if ($scheme) {
818 0         0 setitimer(ITIMER_REAL, $alarm);
819             }
820              
821 0 0       0 if ($fatalFlag) {
822 0         0 $self->fatal("exiting ...");
823             }
824              
825 0         0 return 1;
826              
827             } else {
828              
829 0         0 $self->{errorMessage} = "log file unavailable";
830 0         0 return 0;
831              
832             }
833              
834             } # end of public method "write"
835              
836             sub syslog {
837              
838             # public method to print messages to syslog
839             #
840             # parameters: $self (input) - referent to a logging object
841             # $options (input) - anonymous hash; options
842             #
843             # The following option keys are recognized:
844             #
845             # level ($) - the syslog level
846             # message ($) - the message
847              
848             # input as hidden local variables
849 0     0 1 0 my $self = shift;
850 0 0       0 my $options = @_ ? shift : {};
851              
852             # hidden local variables
853 0         0 my $refType; # a reference type
854             my $option; # an option
855 0         0 my $arg; # an option argument
856 0         0 my $message; # the message
857 0         0 my $level; # the syslog level log
858              
859             # checking options
860 0         0 $refType = ref($options);
861              
862 0 0       0 if (!$refType) {
    0          
863              
864             # just a message
865 0         0 $level = "LOG_DEBUG";
866 0         0 $message = $options;
867              
868             }
869             elsif ($refType eq 'HASH') {
870              
871             # processing options, starting with defaults
872 0         0 $level = "LOG_DEBUG";
873 0         0 $message = q{};
874              
875 0         0 while (($option, $arg) = each %{$options}) {
  0         0  
876 0         0 for ($option) {
877             # the syslog level
878 0 0       0 /^level$/ && do {
879 0         0 $level = $arg;
880 0         0 last;
881             };
882             # the message
883 0 0       0 /^message$/ && do {
884 0         0 $message = $arg;
885 0         0 last;
886             };
887             # default: error option unknown
888 0         0 Hardware::UPS::Perl::Utils::error("option unknown -- $option");
889             }
890             }
891              
892             }
893             else {
894 0         0 Hardware::UPS::Perl::Utils::error("not a hash reference -- <$refType>")
895             }
896              
897             # writing message to syslog
898 0         0 Sys::Syslog::openlog(UPSSCRIPT, "cons.pid", "UPS");
899 0         0 Sys::Syslog::syslog($level, $message);
900 0         0 Sys::Syslog::closelog;
901              
902 0         0 return 1;
903              
904             } # end of public method "syslog"
905              
906             sub setMailTo {
907              
908             # public method to set the mail recipient for e-mails
909             #
910             # parameters: $self (input) - referent to a logging object
911             # $mailto (input) - the mail recipient
912              
913             # input as hidden local variables
914 1     1 1 2 my $self = shift;
915 1         2 my $mailto = shift;
916              
917             # getting old mail recipient
918 1         4 my $oldMailTo = $self->getMailTo();
919              
920             # setting new mail recipient
921 1         2 $self->{mailto} = $mailto;
922              
923             # returning old mail recipient
924 1         1 return $oldMailTo;
925              
926             } # end of public method "setMailTo"
927              
928             sub getMailTo {
929              
930             # public method to get the current mail recipient
931             #
932             # parameters: $self (input) - referent to a logging object
933              
934             # input as hidden local variable
935 1     1 1 1 my $self = shift;
936              
937             # getting mail recipient
938 1 50       5 if (exists $self->{mailto}) {
939 0         0 return $self->{mailto};
940             } else {
941 1         2 return;
942             }
943              
944             } # end of public method "getMailTo"
945              
946             sub sendmail {
947              
948             # public method to send a mail to the current mail recipient
949             #
950             # parameters: $self (input) - referent to a logging object
951             # $options (input) - anonymous hash; options
952             #
953             # The following option keys are recognized:
954             #
955             # MailTo ($) - the mail recipient; optional
956             # Message ($) - the message; optional
957             # Subject ($) - the subject; optional
958              
959             # input as hidden local variables
960 0     0 1 0 my $self = shift;
961 0 0       0 my $options = @_ ? shift : {};
962              
963             # hidden local variables
964 0         0 my $refType; # a reference type
965             my %processOption; # action table to process options
966 0         0 my $option; # an option
967 0         0 my $arg; # an option argument
968 0         0 my $mailTo = q{}; # the mail recipient
969 0         0 my $subject = q{}; # the mail subject
970 0         0 my $message = q{}; # the mail message
971 0         0 my $mail; # the mail object
972             my $mailer_fh; # the mailer
973              
974             # checking options
975 0         0 $refType = ref($options);
976 0 0       0 if ($refType ne 'HASH') {
977 0         0 Hardware::UPS::Perl::Utils::error("not a hash reference -- <$refType>");
978             }
979              
980             # setting up the action table
981             %processOption = (
982             MailTo => sub { # the mail recipient
983 0     0   0 $mailTo = shift;
984             },
985             Message => sub { # the mail message
986 0     0   0 $message = shift;
987             },
988             Subject => sub { # the mail subject
989 0     0   0 $subject = shift;
990             },
991 0         0 );
992              
993             # processing options
994 0         0 PROCESS_OPTIONS:
995 0         0 while (($option, $arg) = each %{$options}) {
996 0 0       0 if (exists $processOption{$option}) {
997 0         0 $processOption{$option}->($arg);
998             }
999             else {
1000             # default: option unknown
1001 0         0 Hardware::UPS::Perl::Utils::error("option unknown -- $option");
1002             }
1003             }
1004              
1005             # checking mail recipient
1006 0 0       0 if (!$mailTo) {
1007 0         0 $mailTo = $self->getMailTo();
1008 0 0 0     0 if (!(defined $mailTo and $mailTo)) {
1009 0         0 $self->{errorMessage} = "no mail recipient available";
1010 0         0 return 0;
1011             }
1012             }
1013            
1014             # sending mail
1015 0 0 0     0 if (defined $subject and $subject) {
1016 0         0 $subject = UPSSCRIPT." at ".UPSHOSTNAME.": ".$subject;
1017             } else {
1018 0         0 $subject = UPSSCRIPT." at ".UPSHOSTNAME;
1019             }
1020              
1021 0         0 $mail = Mail::Send->new(
1022             Subject => $subject,
1023             To => $mailTo ,
1024             );
1025              
1026             $mailer_fh = $mail->open("sendmail")
1027 0 0       0 or do {
1028 0         0 $self->{errorMessage} = "opening sendmail failed";
1029 0         0 return 0;
1030             };
1031              
1032 0 0       0 if ($message) {
1033 0         0 print $mailer_fh "$message\n";
1034             } else {
1035 0         0 print $mailer_fh "event occured at ".scalar(localtime())."\n";
1036             }
1037              
1038             $mailer_fh->close
1039 0 0       0 or do {
1040 0         0 $self->{errorMessage} = "sending mail $subject to $mailTo failed";
1041 0         0 return 0;
1042             };
1043              
1044 0         0 return 1;
1045              
1046             } # end of public method "sendmail"
1047              
1048             sub rotate {
1049              
1050             # public method to force rotation of the log file
1051             #
1052             # parameters: $self (input) - referent to a logging object
1053              
1054             # input as hidden local variable
1055 0     0 1 0 my $self = shift;
1056              
1057             # closing log file
1058 0 0       0 if ($self->_close()) {
1059              
1060             # setting new log file
1061 0         0 $self->_setLogFile(time);
1062              
1063             # opening new log file
1064 0         0 return $self->_open($self->getLogFile());
1065              
1066             }
1067             else {
1068            
1069 0         0 return 1;
1070              
1071             }
1072              
1073             } # end of public method "rotate"
1074              
1075             #==============================================================================
1076             # private methods:
1077             #==============================================================================
1078              
1079             sub _open {
1080              
1081             # private method to open a log file
1082             #
1083             # parameters: $self (input) - referent to a logging object
1084             # $logFile (input) - string, the log file
1085              
1086             # input as hidden local variable
1087 0     0   0 my $self = shift;
1088 0         0 my $logFile = shift;
1089              
1090             # hidden local variable
1091 0         0 my $log_fh; # the log file filehandle
1092              
1093             # already open ?
1094 0 0       0 if ($self->_opened($logFile)) {
1095 0         0 $self->{errorMessage} = "log file $logFile already open";
1096 0         0 return 0;
1097             }
1098              
1099             # opening log file filehandle
1100 0 0       0 if (defined $logFile) {
1101 0         0 $log_fh = new FileHandle $logFile, O_CREAT| O_RDWR | O_TRUNC;
1102             }
1103             else {
1104 0         0 $self->{errorMessage} = "invalid log file $logFile";
1105 0         0 return 0;
1106             }
1107              
1108 0 0       0 if (!defined $log_fh) {
1109 0         0 $self->{errorMessage} = "cannot open log file $logFile -- $!";
1110 0         0 return 0;
1111             }
1112              
1113 0         0 $log_fh->autoflush();
1114              
1115             # creating file link
1116 0         0 my $logFileLink = $self->{_fileBase};
1117              
1118 0 0       0 if ($logFileLink ne $logFile) {
1119              
1120 0 0       0 unlink($logFileLink) if ( -w $logFileLink);
1121              
1122 0 0       0 if (!symlink($logFile, $logFileLink)) {
1123 0         0 undef($log_fh);
1124 0         0 $self->{errorMessage} = "could not create log file link -- $!";
1125 0         0 return 0;
1126             }
1127             }
1128              
1129             # setting handle
1130 0         0 $self->{ handle } = $log_fh;
1131 0         0 $self->{ $logFile } = 1;
1132              
1133 0         0 return 1;
1134              
1135             } # end of private method "_open"
1136              
1137             sub _opened {
1138              
1139             # private method to test the open status of a log file
1140             #
1141             # parameters: $self (input) - referent to an logging object
1142             # $logFile (input) - the log file
1143              
1144             # input as hidden local variable
1145 0     0   0 my $self = shift;
1146 0         0 my $logFile = shift;
1147              
1148             # testing open status
1149 0 0       0 if (defined $logFile) {
1150 0 0       0 if (exists $self->{$logFile}) {
1151 0         0 return 1;
1152             }
1153             else {
1154 0         0 return 0;
1155             }
1156             }
1157             else {
1158 0 0       0 if (exists $self->{handle}) {
1159 0         0 return 1;
1160             }
1161             else {
1162 0         0 return 0;
1163             }
1164             }
1165              
1166             } # end of private method "_opened"
1167              
1168             sub _close {
1169              
1170             # private method to close a log file
1171             #
1172             # parameters: $self (input) - referent to a logging object
1173              
1174             # input as hidden local variable
1175 0     0   0 my $self = shift;
1176              
1177             # getting current log file
1178 0         0 my $logFile = $self->getLogFile();
1179              
1180             # deleting filehandle if open
1181 0 0       0 if ($self->_opened($logFile)) {
1182              
1183             # closing filehandle
1184 0         0 $self->{handle} = undef;
1185              
1186             # deleting filehandle
1187 0         0 delete $self->{ handle };
1188 0 0       0 delete $self->{ $logFile } if (defined $logFile);
1189              
1190 0         0 return 1;
1191              
1192             }
1193             else {
1194              
1195             # error: log file was not open
1196 0         0 $self->{errorMessage} = "log file already closed";
1197              
1198 0         0 return 0;
1199             }
1200              
1201             } # end of private method "_close"
1202              
1203             sub _rotate {
1204              
1205             # private method to rotate a log file
1206             #
1207             # parameters: $self (input) - referent to a logging object
1208              
1209             # input as hidden local variable
1210 0     0   0 my $self = shift;
1211              
1212             # hidden local variables
1213 0         0 my $timestamp = time; # the new timestamp
1214 0         0 my $oldTimestamp; # the old timestamp
1215 0         0 my $doRotate = 0; # rotation flag
1216 0         0 my $scheme; # the rotation scheme
1217             my %processScheme; # the action table to process the scheme given
1218              
1219             # performing rotation due to scheme
1220 0         0 $scheme = $self->getRotationScheme();
1221 0 0       0 if (!defined $scheme) {
1222 0         0 $self->{errorMessage} = "no rotation scheme defined";
1223 0         0 return 0;
1224             }
1225              
1226             # setting up the action table
1227             %processScheme = (
1228             daily => sub { # rotation based on a daily basis
1229              
1230 0     0   0 $oldTimestamp = $self->_getTimestamp();
1231 0         0 my $newDay = time2str("%Y-%m-%d", $timestamp);
1232              
1233 0 0       0 if (defined $oldTimestamp) {
1234 0         0 my $oldDay = time2str("%Y-%m-%d", $oldTimestamp);
1235 0 0       0 if ($newDay ne $oldDay) {
1236 0         0 $doRotate = 1;
1237             }
1238             }
1239              
1240             },
1241             period => sub { # rotation based on period
1242 0     0   0 $oldTimestamp = $self->_getTimestamp();
1243 0         0 my $period = $self->getRotationPeriod();
1244              
1245 0 0 0     0 if (defined $oldTimestamp and defined $period) {
1246 0 0       0 if (abs($timestamp-$oldTimestamp) >= $period) {
1247 0         0 $doRotate = 1;
1248             }
1249             }
1250              
1251             },
1252             size => sub { # rotation based on size
1253 0     0   0 my $logFile = $self->getLogFile();
1254              
1255 0 0       0 if (defined $logFile) {
1256 0         0 my $fileSize = -s $logFile;
1257 0 0       0 if ($fileSize >= $self->getRotationSize()) {
1258 0         0 $doRotate = 1;
1259             }
1260             }
1261              
1262             },
1263 0         0 );
1264              
1265             # processing scheme
1266 0 0       0 if (exists $processScheme{$scheme}) {
1267 0         0 $processScheme{$scheme}->();
1268             }
1269             else {
1270             # default: no rotation at all (assignment not required, but the
1271             # hell know's ...)
1272 0         0 $doRotate = 0;
1273             }
1274              
1275             # performing rotation
1276 0 0       0 if ($doRotate) {
1277              
1278             # closing log file
1279 0 0       0 if ($self->_close()) {
1280              
1281             # setting new log file
1282 0         0 $self->_setLogFile($timestamp);
1283              
1284             # opening new log file
1285 0         0 return $self->_open($self->getLogFile());
1286              
1287             }
1288             else {
1289            
1290             # close failed
1291 0         0 return 0;
1292              
1293             }
1294              
1295             }
1296             else {
1297              
1298             # no rotation required
1299 0         0 return 1;
1300              
1301             }
1302              
1303             } # end of private method "_rotate"
1304              
1305             sub _setLogFile {
1306              
1307             # private method to set the log file
1308             #
1309             # parameters: $self (input) - referent to a logging object
1310             # $timestamp (input) - current timestamp in seconds
1311              
1312             # input as hidden local variable
1313 1     1   2 my $self = shift;
1314 1 50       3 my $timestamp = @_ ? shift : undef;
1315              
1316             # hidden local variables
1317 1         2 my $scheme; # the rotation scheme
1318             my $daystamp; # the timestamp converted to daystamp
1319 0         0 my $oldTimestamp; # the old timestamp
1320 0         0 my $oldDaystamp; # the old timestamp converted to daystamp
1321 0         0 my $logFile; # the log file
1322 0         0 my $oldLogFile; # the previous log file
1323 0         0 my $counter; # the log file counter
1324 0         0 my $name; # log file name
1325 0         0 my $path; # log file path
1326 0         0 my $suffix; # log file suffix
1327              
1328             # getting old log file
1329 1         15 $oldLogFile = $self->getLogFile();
1330              
1331             # no timestamp, no log file
1332 1 50       3 if (!defined $timestamp) {
1333 1         3 $self->{logfile} = undef;
1334 1         3 return $oldLogFile;
1335             }
1336              
1337             # getting rotation scheme
1338 0         0 $scheme = $self->getRotationScheme();
1339              
1340 0 0 0     0 if (defined $scheme and !$ROTATION_SCHEME{$scheme}) {
1341             # no rotation, setting log file to log file base
1342 0         0 $self->{logfile} = $self->{_fileBase};
1343 0         0 return $oldLogFile;
1344             }
1345              
1346             # setting timestamp and log file
1347 0         0 $daystamp = time2str("%Y-%m-%d", $timestamp);
1348 0         0 $oldTimestamp = $self->_setTimestamp($timestamp);
1349              
1350 0 0       0 if (defined $oldTimestamp) {
1351 0         0 $oldDaystamp = time2str("%Y-%m-%d", $oldTimestamp);
1352             }
1353             else {
1354 0         0 $oldDaystamp = $daystamp;
1355             }
1356              
1357 0         0 $logFile = $self->{_fileBase}.q{.}.$daystamp;
1358              
1359             # getting new log file counter
1360 0 0       0 if (defined $oldLogFile) {
1361              
1362 0 0       0 if ($daystamp eq $oldDaystamp) {
1363             # still the same day
1364 0         0 ($name, $path, $suffix) = fileparse($oldLogFile, '\.[0-9]$');
1365 0         0 ($counter = $suffix) =~ s/\.//g;;
1366             }
1367             else {
1368             # we have a roll over
1369 0         0 $counter = -1;
1370             }
1371              
1372             }
1373             else {
1374              
1375 0         0 ($name, $path, $suffix) = fileparse($logFile, '');
1376              
1377 0         0 my @filelist = ();
1378 0 0   0   0 find(sub {/^$name\.[0-9]$/ && push(@filelist, $_)}, $path);
  0         0  
1379              
1380 0 0       0 if (@filelist) {
1381            
1382             # we have some log files already
1383 0         0 $oldLogFile = pop(@filelist);
1384 0         0 ($name, $path, $suffix) = fileparse($oldLogFile, '\.[0-9]$');
1385 0         0 ($counter = $suffix) =~ s/\.//g;;
1386              
1387             }
1388             else {
1389             # no log files around, init ...
1390 0         0 $counter = -1;
1391             }
1392             }
1393              
1394 0 0       0 if ($counter < 9) {
1395 0         0 $counter++;
1396             }
1397             else {
1398 0         0 $counter = 0;
1399             }
1400              
1401             # setting log file
1402 0         0 $self->{logfile} = $logFile.".".$counter;
1403              
1404 0         0 return $oldLogFile;
1405              
1406             } # end of private method "_setLogFile"
1407              
1408             sub _setRotationPeriod {
1409              
1410             # private method to set the rotation period
1411             #
1412             # parameters: $self (input) - referent to a logging object
1413             # $period (input) - the rotation period
1414              
1415             # input as hidden local variables
1416 0     0   0 my $self = shift;
1417 0         0 my $period = shift;
1418              
1419             # getting old rotation period
1420 0         0 my $oldPeriod = $self->getRotationPeriod();
1421              
1422             # setting new rotation period
1423 0         0 $self->{period} = $period;
1424              
1425             # returning old rotation period
1426 0         0 return $oldPeriod;
1427              
1428             } # end of private method "_setRotationPeriod"
1429              
1430             sub _setRotationSize {
1431              
1432             # private method to set the rotation size
1433             #
1434             # parameters: $self (input) - referent to a logging object
1435             # $size (input) - the rotation size
1436              
1437             # input as hidden local variables
1438 0     0   0 my $self = shift;
1439 0         0 my $size = shift;
1440              
1441             # getting old rotation size
1442 0         0 my $oldSize = $self->getRotationSize();
1443              
1444             # setting new rotation size
1445 0         0 $self->{size} = $size;
1446              
1447             # returning old rotation size
1448 0         0 return $oldSize;
1449              
1450             } # end of private method "_setRotationSize"
1451              
1452             sub _setRotationScheme {
1453              
1454             # private method to set the rotation scheme
1455             #
1456             # parameters: $self (input) - referent to a logging object
1457             # $scheme (input) - the rotation scheme:
1458             # $scheme = none - no rotation at all;
1459             # this is the default;
1460             # = daily - rotation on a daily
1461             # basis;
1462             # = period - rotation based on given
1463             # period;
1464             # = size - rotation based on given
1465             # size.
1466              
1467             # input as hidden local variables
1468 1     1   2 my $self = shift;
1469 1         1 my $scheme = shift;
1470              
1471             # getting old rotation scheme
1472 1         6 my $oldScheme = $self->getRotationScheme();
1473              
1474             # setting new rotation scheme
1475 1         2 $self->{scheme} = $scheme;
1476              
1477             # returning old rotation scheme
1478 1         1 return $oldScheme;
1479              
1480             } # end of private method "_setRotationScheme"
1481              
1482             sub _setTimestamp {
1483              
1484             # private method to set the timestamp
1485             #
1486             # parameters: $self (input) - referent to a logging object
1487             # $timestamp (input) - the timestamp
1488              
1489             # input as hidden local variables
1490 0     0     my $self = shift;
1491 0           my $timestamp = shift;
1492              
1493             # getting old timestamp
1494 0           my $oldTimestamp = $self->_getTimestamp();
1495              
1496             # setting new timestamp
1497 0           $self->{_timestamp} = $timestamp;
1498              
1499             # returning old rotation period
1500 0           return $oldTimestamp;
1501              
1502             } # end of private method "_setTimestamp"
1503              
1504             sub _getTimestamp {
1505              
1506             # private method to get the current timestamp
1507             #
1508             # parameters: $self (input) - referent to a logging object
1509              
1510             # input as hidden local variable
1511 0     0     my $self = shift;
1512              
1513             # getting timestamp
1514 0 0         if (exists $self->{_timestamp}) {
1515 0           return $self->{_timestamp};
1516             } else {
1517 0           return;
1518             }
1519              
1520             } # end of private method "_getTimestamp"
1521              
1522             #==============================================================================
1523             # package return:
1524             #==============================================================================
1525             1;
1526              
1527             __END__