File Coverage

blib/lib/UniLog.pm
Criterion Covered Total %
statement 109 165 66.0
branch 26 70 37.1
condition 4 15 26.6
subroutine 44 57 77.1
pod 27 49 55.1
total 210 356 58.9


line stmt bran cond sub pod time code
1             package UniLog;
2              
3 1     1   6158 use strict;
  1         2  
  1         46  
4 1     1   7 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS @EXPORT_FAIL);
  1         2  
  1         247  
5              
6             #$^W++;
7              
8             require Exporter;
9              
10             @ISA = qw(Exporter);
11             # Items to export into callers namespace by default. Note: do not export
12             # names by default without a very good reason. Use EXPORT_OK instead.
13             # Do not simply export all your public functions/methods/constants.
14             @EXPORT = qw(
15             );
16              
17             %EXPORT_TAGS = ('levels' => [qw(LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR
18             LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG )],
19             'options' => [qw(LOG_CONS LOG_NDELAY LOG_PERROR LOG_PID)],
20             'facilities' => [qw(LOG_AUTH LOG_CRON LOG_DAEMON
21             LOG_KERN LOG_LPR LOG_MAIL LOG_NEWS
22             LOG_SECURITY LOG_SYSLOG LOG_USER LOG_UUCP
23             LOG_LOCAL0 LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3
24             LOG_LOCAL4 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7)],
25             'functions' => [qw(SafeStr)],
26             'syslog' => [qw(syslog)],
27             'nosyslog' => [qw(nosyslog)],
28             );
29              
30             foreach (keys(%EXPORT_TAGS))
31             { push(@{$EXPORT_TAGS{'all'}}, @{$EXPORT_TAGS{$_}}); };
32              
33             $EXPORT_TAGS{'all'}
34             and @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
35              
36             @EXPORT_FAIL = qw(syslog nosyslog); # hook to enable/disable syslog
37              
38             $VERSION = '0.14';
39              
40 1     1   5 use Carp qw(carp croak cluck confess);
  1         14  
  1         71  
41 1     1   916 use POSIX;
  1         9116  
  1         9  
42 1     1   6067 use IO::File;
  1         41612  
  1         1407  
43 1     1   16 use File::Path;
  1         3  
  1         69  
44 1     1   5 use File::Basename;
  1         2  
  1         2778  
45              
46 5     5 0 110 sub LOG_CONS() { return 2; };
47 4     4 0 36 sub LOG_NDELAY() { return 8; };
48 5     5 0 1782 sub LOG_PID() { return 1; };
49             my %LogOptions = (LOG_CONS() => LOG_CONS(),
50             LOG_NDELAY() => LOG_NDELAY(),
51             LOG_PID() => LOG_PID(),
52             );
53             my $CalcOpt = sub
54             {
55             my $Result = 0;
56             foreach (keys(%LogOptions))
57             {
58             if ($_[0] & $_)
59             { $Result = $Result | $LogOptions{$_}; };
60             };
61             return $Result;
62             };
63              
64             #
65             # Define log levels
66             my @LogLevels = (0, 1, 2, 3, 4, 5, 6, 7);
67             #
68 1     1 1 36 sub LOG_EMERG() { return 0; };
69 1     1 1 30 sub LOG_ALERT() { return 1; };
70 1     1 1 26 sub LOG_CRIT() { return 2; };
71 1     1 1 26 sub LOG_ERR() { return 3; };
72 1     1 1 23 sub LOG_WARNING() { return 4; };
73 1     1 1 23 sub LOG_NOTICE() { return 5; };
74 5     5 1 47 sub LOG_INFO() { return 6; };
75 2     2 1 55 sub LOG_DEBUG() { return 7; };
76              
77             #
78             # Define log facilities
79             my %LogFacilities = ('LOG_AUTH' => 1,
80             'LOG_AUTHPRIV' => 2,
81             'LOG_CRON' => 3,
82             'LOG_DAEMON' => 4,
83             'LOG_FTP' => 5,
84             'LOG_KERN' => 6,
85             'LOG_LPR' => 7,
86             'LOG_MAIL' => 8,
87             'LOG_NEWS' => 9,
88             'LOG_SYSLOG' => 10,
89             'LOG_USER' => 11,
90             'LOG_UUCP' => 12,
91             'LOG_LOCAL0' => 13,
92             'LOG_LOCAL1' => 14,
93             'LOG_LOCAL2' => 15,
94             'LOG_LOCAL3' => 16,
95             'LOG_LOCAL4' => 17,
96             'LOG_LOCAL5' => 18,
97             'LOG_LOCAL6' => 19,
98             'LOG_LOCAL7' => 20,
99             );
100             #
101 1     1 0 30 sub LOG_AUTH() { return 'LOG_AUTH'; };
102             #sub LOG_AUTHPRIV() { return 'LOG_AUTHPRIV'; };
103 1     1 0 23 sub LOG_CRON() { return 'LOG_CRON'; };
104 1     1 0 22 sub LOG_DAEMON() { return 'LOG_DAEMON'; };
105             #sub LOG_FTP() { return 'LOG_FTP'; };
106 1     1 0 23 sub LOG_KERN() { return 'LOG_KERN'; };
107 1     1 0 22 sub LOG_LPR() { return 'LOG_LPR'; };
108 1     1 0 22 sub LOG_MAIL() { return 'LOG_MAIL'; };
109 1     1 0 21 sub LOG_NEWS() { return 'LOG_NEWS'; };
110 1     1 0 29 sub LOG_SYSLOG() { return 'LOG_SYSLOG'; };
111 3     3 0 39 sub LOG_USER() { return 'LOG_USER'; };
112 1     1 0 22 sub LOG_UUCP() { return 'LOG_UUCP'; };
113 1     1 0 23 sub LOG_LOCAL0() { return 'LOG_LOCAL0'; };
114 1     1 0 43 sub LOG_LOCAL1() { return 'LOG_LOCAL1'; };
115 1     1 0 22 sub LOG_LOCAL2() { return 'LOG_LOCAL2'; };
116 1     1 0 22 sub LOG_LOCAL3() { return 'LOG_LOCAL3'; };
117 1     1 0 23 sub LOG_LOCAL4() { return 'LOG_LOCAL4'; };
118 1     1 0 22 sub LOG_LOCAL5() { return 'LOG_LOCAL5'; };
119 1     1 0 22 sub LOG_LOCAL6() { return 'LOG_LOCAL6'; };
120 1     1 0 33 sub LOG_LOCAL7() { return 'LOG_LOCAL7'; };
121              
122             # Define syslog functions
123             my $OpenLog = undef;
124             my $CloseLog = undef;
125             my $PutMsg = undef;
126              
127             my $SyslogEnabled = 1;
128              
129             my $InitSyslog = sub
130             {
131             if ( $^O =~ m/win32/i )
132             {
133             if (!Win32::IsWinNT())
134             {
135             #$OpenLog = sub { return 1; };
136             #$CloseLog = sub { return 1; };
137             #$PutMsg = sub { return 1; };
138             $SyslogEnabled = 0;
139             carp "Win32::EventLog is not supporting Win32 systems other WinNT. Syslog functionality disabled\n";
140             return;
141             };
142            
143             eval 'use Win32::EventLog;
144             $OpenLog = sub
145             {
146             my ($Ident, $Options, $Facility) = @_;
147             if ($Options & LOG_PID())
148             { $Ident .= "[$$]" };
149             return Win32::EventLog->new($Ident, $ENV{ComputerName});
150             };
151             $CloseLog = sub
152             {
153             $_[0]->{Handler}->Close();
154             };
155             $PutMsg = sub
156             { $_[0]->{Handler}->Report({EventType => $_[1],
157             Strings => $_[2],
158             Category => $_[0]->{"Facility"},
159             EventID => 0,
160             Data => "",
161             });
162             };
163             $LogLevels[LOG_EMERG()] = EVENTLOG_ERROR_TYPE;
164             $LogLevels[LOG_ALERT()] = EVENTLOG_ERROR_TYPE;
165             $LogLevels[LOG_CRIT()] = EVENTLOG_ERROR_TYPE;
166             $LogLevels[LOG_ERR()] = EVENTLOG_ERROR_TYPE;
167             $LogLevels[LOG_WARNING()] = EVENTLOG_WARNING_TYPE;
168             $LogLevels[LOG_NOTICE()] = EVENTLOG_INFORMATION_TYPE;
169             $LogLevels[LOG_INFO()] = EVENTLOG_INFORMATION_TYPE;
170             $LogLevels[LOG_DEBUG()] = EVENTLOG_INFORMATION_TYPE;
171             ';
172             }
173             else
174             {
175 1     1   794 eval 'use Unix::Syslog;
  1         1066  
  1         1679  
176             $OpenLog = sub {
177             my ($Ident, $Options, $Facility) = @_;
178             Unix::Syslog::openlog($Ident, $Options, $Facility);
179             return 1;
180             };
181             $CloseLog = sub { Unix::Syslog::closelog; };
182             $PutMsg = sub { Unix::Syslog::syslog($_[1], "%s", $_[2]); };
183             # Set real log levels
184             $LogLevels[LOG_EMERG()] = Unix::Syslog::LOG_EMERG;
185             $LogLevels[LOG_ALERT()] = Unix::Syslog::LOG_ALERT;
186             $LogLevels[LOG_CRIT()] = Unix::Syslog::LOG_CRIT;
187             $LogLevels[LOG_ERR()] = Unix::Syslog::LOG_ERR;
188             $LogLevels[LOG_WARNING()] = Unix::Syslog::LOG_WARNING;
189             $LogLevels[LOG_NOTICE()] = Unix::Syslog::LOG_NOTICE;
190             $LogLevels[LOG_INFO()] = Unix::Syslog::LOG_INFO;
191             $LogLevels[LOG_DEBUG()] = Unix::Syslog::LOG_DEBUG;
192             #
193             # Set log options
194             $LogOptions{LOG_CONS()} = Unix::Syslog::LOG_CONS;
195             $LogOptions{LOG_NDELAY()} = Unix::Syslog::LOG_NDELAY;
196             $LogOptions{LOG_PID()} = Unix::Syslog::LOG_PID;
197             #
198             # Set log facilities
199             $LogFacilities{LOG_AUTH()} = Unix::Syslog::LOG_AUTH;
200             #$LogFacilities{LOG_AUTHPRIV()} = Unix::Syslog::LOG_AUTHPRIV;
201             $LogFacilities{LOG_CRON()} = Unix::Syslog::LOG_CRON;
202             $LogFacilities{LOG_DAEMON()} = Unix::Syslog::LOG_DAEMON;
203             #$LogFacilities{LOG_FTP()} = Unix::Syslog::LOG_FTP;
204             $LogFacilities{LOG_KERN()} = Unix::Syslog::LOG_KERN;
205             $LogFacilities{LOG_LPR()} = Unix::Syslog::LOG_LPR;
206             $LogFacilities{LOG_MAIL()} = Unix::Syslog::LOG_MAIL;
207             $LogFacilities{LOG_NEWS()} = Unix::Syslog::LOG_NEWS;
208             $LogFacilities{LOG_SYSLOG()} = Unix::Syslog::LOG_SYSLOG;
209             $LogFacilities{LOG_USER()} = Unix::Syslog::LOG_USER;
210             $LogFacilities{LOG_UUCP()} = Unix::Syslog::LOG_UUCP;
211             $LogFacilities{LOG_LOCAL0()} = Unix::Syslog::LOG_LOCAL0;
212             $LogFacilities{LOG_LOCAL1()} = Unix::Syslog::LOG_LOCAL1;
213             $LogFacilities{LOG_LOCAL2()} = Unix::Syslog::LOG_LOCAL2;
214             $LogFacilities{LOG_LOCAL3()} = Unix::Syslog::LOG_LOCAL2;
215             $LogFacilities{LOG_LOCAL4()} = Unix::Syslog::LOG_LOCAL4;
216             $LogFacilities{LOG_LOCAL5()} = Unix::Syslog::LOG_LOCAL5;
217             $LogFacilities{LOG_LOCAL6()} = Unix::Syslog::LOG_LOCAL6;
218             $LogFacilities{LOG_LOCAL7()} = Unix::Syslog::LOG_LOCAL7;
219             ';
220             };
221            
222             # These linea are necessary!
223             foreach (@LogLevels) { my $tmpVar = $_; };
224             foreach (keys(%LogOptions)) { my $tmpVar = $_; };
225             foreach (keys(%LogFacilities)) { my $tmpVar = $_; };
226            
227             if ($@) { croak $@; };
228             if ($^W) { carp "Syslog functionality enabled\n"; };
229             my $tmpVar = $OpenLog.$CloseLog.$PutMsg; # This string is necessary.
230             return 1;
231             };
232              
233             sub export_fail
234             {
235 1     1 0 145 shift;
236 1 50       5 if ($_[0] eq 'nosyslog')
    50          
237             {
238 0         0 shift;
239             #$InitSyslog = undef;
240 0         0 $SyslogEnabled = 0;
241 0 0       0 if ($^W) { carp "Syslog functionality disabled\n"; };
  0         0  
242             }
243             elsif ($_[0] eq 'syslog')
244             {
245 1         1 shift;
246 1 50 33     6 if ($InitSyslog && !$OpenLog)
247 1         2 { &{$InitSyslog}(); };
  1         2  
248             }
249 1         138 return @_;
250             };
251              
252             # Preloaded methods go here.
253              
254             my $FileReOpen = sub
255             {
256             my ($self) = @_;
257              
258             my @tm = POSIX::localtime(POSIX::time());
259             my $NewName = POSIX::strftime($self->{'LogFileNameTemplate'}, @tm)
260             or confess "Can not create log file name from template \"".SafeStr($self->{'LogFileNameTemplate'})."\"\n";
261              
262             if ($self->{'LogFileHandler'} &&
263             defined($self->{'LogFileNameCurrent'}) &&
264             ($NewName eq $self->{'LogFileNameCurrent'}))
265             { return $self->{'LogFileNameCurrent'}; };
266              
267             $self->{'LogFileNameCurrent'} = $NewName;
268            
269             if ($self->{'LogFileHandler'})
270             { $self->{'LogFileHandler'}->close(); };
271              
272             if (!length($NewName))
273             { return $NewName; };
274              
275             File::Path::mkpath(File::Basename::dirname($NewName), 0, $self->{'DirPerms'});
276              
277             $self->{'LogFileHandler'} = IO::File->new($NewName, ($self->{'Truncate'} ? '>' : '>>'))
278             or return;
279             if (chmod($self->{'FilePerms'}, $NewName) < 1)
280             { carp sprintf("Can not change file \"%s\" permissions to '%04o'\n", SafeStr($NewName), $self->{'FilePerms'}); };
281              
282             autoflush {$self->{'LogFileHandler'}} 1;
283              
284             return $self->{'LogFileHandler'};
285             };
286              
287             sub new($%)
288             {
289 1     1 1 9 my ($class, %LogParam) = @_;
290              
291 1 50 33     13 if ($SyslogEnabled && !$OpenLog)
292 0         0 { &{$InitSyslog}(); };
  0         0  
293              
294 1         4 my %DefParam = ('Ident' => $0,
295             'Level' => 6,
296             'StdErr' => 0,
297             'SysLog' => 1,
298             'DirPerms' => 0750,
299             'FilePerms' => 0640,
300             'Truncate' => 0,
301             'Options' => LOG_PID() | LOG_CONS(),
302             'Facility' => LOG_USER(),
303             'SafeStr' => 1,
304             );
305              
306 1         7 foreach (keys(%DefParam))
307             {
308 10 100       20 if (!defined($LogParam{$_}))
309 5         12 { $LogParam{$_} = $DefParam{$_}; };
310             };
311              
312 1 50       6 if (!defined($LogFacilities{$LogParam{'Facility'}}))
313             {
314 0         0 cluck sprintf("Unknown facility \"%s\", use the default facility \"%s\"\n", SafeStr($LogParam{'Facility'}), SafeStr($DefParam{'Facility'}));
315 0         0 $LogParam{'Facility'} = $DefParam{'Facility'};
316             };
317            
318 1   33     5 my $self = {'Ident' => SafeStr($LogParam{Ident}),
319             'Level' => $LogParam{'Level'},
320             'Facility' => $LogFacilities{$LogParam{'Facility'}},
321             'StdErr' => $LogParam{'StdErr'},
322             'SysLog' => ($LogParam{'SysLog'} && $SyslogEnabled),
323             'SafeStr' => $LogParam{'SafeStr'},
324             'LogFileNameTemplate' => $LogParam{'LogFile'},
325             'Truncate' => $LogParam{'Truncate'},
326             'DirPerms' => $LogParam{'DirPerms'},
327             'FilePerms' => $LogParam{'FilePerms'},
328             'LogFileNameCurrent' => '',
329             'LogFileHandler' => undef,
330             };
331              
332 1 50       6 if ($OpenLog)
333             {
334 1         3 $self->{'Handler'} = &{$OpenLog}($self->{'Ident'}, &{$CalcOpt}($LogParam{'Options'}), $self->{'Facility'});
  1         58  
  1         5  
335 1 50       7 if (!$self->{'Handler'})
336             {
337 0         0 $! .= ' '.$@;
338 0         0 return;
339             };
340             };
341              
342 1 50       6 if (defined($self->{'LogFileNameTemplate'}))
343             {
344 1         2 &{$FileReOpen}($self);
  1         5  
345 1 50       8 if (!defined($self->{'LogFileNameTemplate'}))
346             {
347 0         0 $! = sprintf("Can not open file \"%s\": %s", SafeStr($self->{'LogFileNameCurrent'}), $!);
348 0         0 Close($self);
349 0         0 return;
350             };
351             };
352              
353 1         9 return bless $self => $class;
354             };
355              
356             sub emergency($$@)
357 0     0 1 0 { return Message(shift, LOG_EMERG(), @_); };
358             sub alert($$@)
359 0     0 1 0 { return Message(shift, LOG_ALERT(), @_); };
360             sub critical($$@)
361 0     0 1 0 { return Message(shift, LOG_CRIT(), @_); };
362             sub error($$@)
363 0     0 1 0 { return Message(shift, LOG_ERR(), @_); };
364             sub warning($$@)
365 0     0 1 0 { return Message(shift, LOG_WARNING(), @_); };
366             sub notice($$@)
367 0     0 1 0 { return Message(shift, LOG_NOTICE(), @_); };
368             sub info($$@)
369 0     0 1 0 { return Message(shift, LOG_INFO(), @_); };
370             sub debug($$@)
371 0     0 1 0 { return Message(shift, LOG_DEBUG(), @_); };
372              
373             sub Message($$$@)
374             {
375 4     4 1 12 my ($self, $Level, $Format, @Args) = @_;
376              
377 4 50       17 if ($Level < 0)
    50          
378             {
379 0 0       0 if ($^W) { cluck "Log level \"$Level\" adjusted from \"$Level\" to \"0\"\n"; };
  0         0  
380 0         0 $Level = 0;
381             }
382             elsif ($Level > $#LogLevels)
383             {
384 0 0       0 if ($^W) { cluck "Log level \"$Level\" adjusted from \"$Level\" to \"$#LogLevels\"\n"; };
  0         0  
385 0         0 $Level = $#LogLevels;
386             };
387              
388 4 50       18 if ($Level <= $self->{Level})
389             {
390 4 50       22 my $Str = $self->{'SafeStr'} ? SafeStr(sprintf($Format, @Args)) : sprintf($Format, @Args);
391              
392 4 50       13 if ($self->{'StdErr'})
393 4         244 { print STDERR localtime()." $Level $Str\n"; };
394              
395 4 50       17 if ($PutMsg)
396 4         6 { &{$PutMsg}($self, $LogLevels[$Level], $Str); };
  4         165  
397              
398 4 50       303 if (defined($self->{'LogFileNameTemplate'}))
399             {
400 4 50       7 if (!(&{$FileReOpen}($self)))
  4         10  
401             {
402 0         0 $! = sprintf("Can not open file \"%s\": %s", SafeStr($self->{'LogFileNameCurrent'}), $!);
403 0         0 return;
404             };
405 4 50       5 if (!(print {$self->{'LogFileHandler'}} localtime()." $Level $Str\n"))
  4         173  
406             {
407 0         0 $! = sprintf("Can not write to the file \"%s\": %s", SafeStr($self->{'LogFileNameCurrent'}), $!);
408 0         0 return;
409             };
410             };
411             };
412 4         12 return 1;
413             };
414              
415             sub Level($$)
416             {
417 0     0 1 0 my $Return = $_[0]->{Level};
418 0 0       0 if (defined($_[1]))
419 0         0 { $_[0]->{Level} = $_[1]; };
420 0         0 return $Return;
421             };
422              
423             sub SysLog($$)
424             {
425 1   33 1 1 10 my $Return = ($_[0]->{'SysLog'} && $SyslogEnabled);
426 1 50       4 if (defined($_[1]))
427 0   0     0 { $_[0]->{'SysLog'} = ($_[1] && $SyslogEnabled); };
428 1         2 return $Return;
429             };
430              
431             sub StdErr($$)
432             {
433 0     0 1 0 my $Return = $_[0]->{'StdErr'};
434 0 0       0 if (defined($_[1]))
435 0         0 { $_[0]->{'StdErr'} = $_[1]; };
436 0         0 return $Return;
437             };
438              
439             sub LogFile($$)
440             {
441 1 50   1 1 5 if (defined($_[1]))
442 0         0 { $_[0]->{'LogFileNameTemplate'} = $_[1]; };
443 1 50       4 if (defined($_[2]))
444 0         0 { $_[0]->{'FilePerms'} = $_[2]; };
445 1         5 return $_[0]->{'LogFileNameCurrent'};
446             };
447              
448             sub Permissions($$$)
449             {
450 0     0 1 0 my @Return = ($_[0]->{'FilePerms'}, $_[0]->{'DirPerms'});
451 0 0       0 if (defined($_[1]))
452 0         0 { $_[0]->{'FilePerms'} = $_[1]; };
453 0 0       0 if (defined($_[2]))
454 0         0 { $_[0]->{'DirPerms'} = $_[2]; };
455 0 0       0 return (wantarray ? @Return : $Return[0]);
456             };
457              
458             sub Truncate($$)
459             {
460 0     0 1 0 my $Return = $_[0]->{'Truncate'};
461 0 0       0 if (defined($_[1]))
462 0         0 { $_[0]->{'Truncate'} = $_[1]; };
463 0         0 return $Return;
464             };
465              
466             sub CloseLogFile
467             {
468 0 0   0 1 0 if ($_[0]->{'LogFileHandler'})
469 0         0 { $_[0]->{'LogFileHandler'}->close(); };
470 0         0 $_[0]->{'LogFileHandler'} = undef;
471             };
472              
473             sub Close($)
474             {
475 1 50   1 1 9 if ($CloseLog)
476 1         2 { &{$CloseLog}($_[0]); };
  1         60  
477 1         3 $_[0]->{Handler} = undef;
478             #
479 1 50       4 if (defined($_[0]->{'LogFileHandler'}))
480 1         11 { $_[0]->{'LogFileHandler'}->close(); };
481 1         19 $_[0]->{'LogFileHandler'} = undef;
482             };
483              
484             sub SafeStr($)
485             {
486 5 50   5 1 15 my $Str = shift
487             or return '!UNDEF!';
488 5         14 $Str =~ s{ ([\x00-\x1f\xff\\]) } { sprintf("\\x%2.2X", ord($1)) }gsex;
  0         0  
489 5         23 return $Str;
490             };
491              
492             1;
493             __END__