Add timestamps when logging messages.
[people/stevee/guardian.git] / modules / Logger.pm
1 package Guardian::Logger;
2 use strict;
3 use warnings;
4
5 use Exporter qw(import);
6
7 our @EXPORT_OK = qw(New Log GetLogLevels);
8
9 use Sys::Syslog qw(:DEFAULT setlogsock);
10 use POSIX qw(strftime);
11
12 # Hash which stores all supported log levels and their priority.
13 my %loglevels = (
14         'off' => '0',
15         'err' => '1',
16         'info' => '1',
17         'debug' => '2',
18 );
19
20 # This hash contains the supported log facilities and their corresponding subroutines.
21 my %logfacilities = (
22         "console" => \&LogFacilityConsole,
23         "file" => \&LogFacilityFile,
24         "syslog" => \&LogFacilitySyslog,
25 );
26
27
28 #
29 ## The "Init" (Logger) function.
30 #
31 ## This function is responsible to initialize the Logger as a class based object.
32 ## It has to be called once before logging can be done.
33 #
34 ## The following arguments must be passed, when initializing a new Logger:
35 ## "LogLevel" and "LogFacility" with valid values from above.
36 #
37 sub Init (%) {
38         my ( $class, %args ) = @_;
39         my $self = \%args;
40
41         # Fail, if some critical arguments are missing.
42         unless ((exists($self->{LogLevel})) && (exists($self->{LogFacility}))) {
43                 die "Could not initialize the Logger: Too less arguments are given.\n";
44         }
45
46         # Use bless to make "$self" to an object of class "$class".
47         bless($self, $class);
48
49         # Return the class object.
50         return $self;
51 }
52
53 #
54 ## The main "Log" function.
55 #
56 ## This function is used to handle the messages which are generated on various 
57 ## points in the main programm or its modules. Those messages will contain usefull
58 ## information or deeper details about errors.
59 #
60 ## The Log function takes care about the configured loglevel and transmitts the
61 ## log messages to the configured log facility.
62 #
63 sub Log ($$) {
64         my $self = shift;
65         my ($level, $message) = @_;
66
67         # Check if we got an invalid loglevel.
68         unless(exists($loglevels{$level})) {
69                 &Log("err", "The logger has been called with an invalid loglevel ($level)!\n");
70                 return;
71         }
72
73         # Get value for the current used loglevel.
74         my $current_level = $loglevels{$self->{LogLevel}};
75
76         # Get value for the required loglevel.
77         my $required_level = $loglevels{$level};
78
79         # Compare the current and required level to determine,
80         # if the message should be handled.
81         if ($current_level >= $required_level) {
82                 # Get the facility, which should be used.
83                 my $use_facility = $self->{LogFacility};
84
85                 # Transmit log message to the correct log facility.
86                 $logfacilities{$use_facility}->($self, $level, $message);
87         }
88 }
89
90 #
91 ## GetLogLevels function.
92 #
93 ## This really simple function just returns the hash which
94 ## contains all supported log levels.
95 #
96 sub GetLogLevels () {
97         # Nothing to do, just return the loglevels hash.
98         return %loglevels;
99 }
100
101 #
102 ## LogFacilityConsole function.
103 #
104 ## This is a very simple log facility which just prints the given log
105 ## message to STDOUT.
106 #
107 sub LogFacilityConsole ($$) {
108         my $self = shift;
109         my ($type, $message) = @_;
110
111         # Get current date and time and format like: "Jan 01 00:00:01"
112         my $now = strftime "%b %e %H:%M:%S", localtime();
113
114         # Print message on STDOUT.
115         print STDOUT "$now \[$type\] $message\n";
116 }
117
118 #
119 ## LogFacilitySyslog function.
120 #
121 ## This log facility sends a given log message to the system log service (syslog).
122 #
123 sub LogFacilitySyslog ($$) {
124         my $self = shift;
125         my ($type, $message) = @_;
126
127         # The syslog function works best with an array based input,
128         # so generate one before passing the message details to syslog.
129         my @syslog = ("$type", "<$type> $message");
130
131         # Establish the connection to the syslog service.
132         openlog('guardian', 'cons,pid', 'user');
133
134         # Send the log message.
135         syslog(@syslog);
136
137         # Close the log handle.
138         closelog();
139 }
140
141 #
142 ## LogFacilityFile function.
143 #
144 ## This log facility will write any given log messages to a specified log file.
145 #
146 sub LogFacilityFile ($$) {
147         my $self = shift;
148         my ($type, $message) = @_;
149
150         # Get current date and time and format like: "Jan 01 00:00:01"
151         my $now = strftime "%b %e %H:%M:%S", localtime();
152
153         # Open the logfile for writing.
154         open(LOGFILE, '>>', $self->{LogFile}) or die "Could not write to $self->{LogFile}: $!\n";
155
156         # Write log message to file.
157         print LOGFILE "$now \[$type\] $message\n";
158
159         # Close filehandle.
160         close(FILE);
161 }
162
163 1;