1# -*- perl -*-
2#
3#   $Id: Log.pm,v 1.3 1999/09/26 14:50:13 joe Exp $
4#
5#   Net::Daemon - Base class for implementing TCP/IP daemons
6#
7#   Copyright (C) 1998, Jochen Wiedmann
8#                       Am Eisteich 9
9#                       72555 Metzingen
10#                       Germany
11#
12#                       Phone: +49 7123 14887
13#                       Email: joe@ispsoft.de
14#
15#   All rights reserved.
16#
17#   You may distribute this package under the terms of either the GNU
18#   General Public License or the Artistic License, as specified in the
19#   Perl README file.
20#
21############################################################################
22
23require 5.004;
24use strict;
25
26
27package Net::Daemon::Log;
28
29$Net::Daemon::Log::VERSION = '0.01';
30
31
32############################################################################
33#
34#   Name:    Log (Instance method)
35#
36#   Purpose: Does logging
37#
38#   Inputs:  $self - Server instance
39#
40#   Result:  TRUE, if the client has successfully authorized, FALSE
41#            otherwise.
42#
43############################################################################
44
45
46sub OpenLog($) {
47    my $self = shift;
48    return 1 unless ref($self);
49    return $self->{'logfile'} if defined($self->{'logfile'});
50    if ($Config::Config{'archname'} =~ /win32/i) {
51	require Win32::EventLog;
52	$self->{'eventLog'} = Win32::EventLog->new(ref($self), '')
53	    or die "Cannot open EventLog:" . &Win32::GetLastError();
54	$self->{'$eventId'} = 0;
55    } else {
56	eval { require Sys::Syslog };
57	if ($@) {
58	    die "Cannot open Syslog: $@";
59	}
60	if ($^O ne 'solaris'  &&  $^O ne 'freebsd'  &&
61	    defined(&Sys::Syslog::setlogsock)  &&
62	    eval { &Sys::Syslog::_PATH_LOG() }) {
63	    &Sys::Syslog::setlogsock('unix');
64	}
65	&Sys::Syslog::openlog($self->{'logname'} || ref($self), 'pid',
66			      $self->{'facility'} || 'daemon');
67    }
68    $self->{'logfile'} = 0;
69}
70
71sub Log ($$$;@) {
72    my($self, $level, $format, @args) = @_;
73    my $logfile = !ref($self) || $self->OpenLog();
74
75    my $tid = '';
76    if (ref($self)  &&  $self->{'mode'}) {
77	if ($self->{'mode'} eq 'ithreads') {
78	    if (my $sthread = threads->self()) {
79		$tid = $sthread->tid() . ", ";
80	    }
81	} elsif ($self->{'mode'} eq 'threads') {
82      if (my $sthread = Thread->self()) {
83	  $tid = $sthread->tid() . ", ";
84      }
85    }
86    }
87    if ($logfile) {
88	my $logtime = $self->LogTime();
89	if (ref($logfile)) {
90	    $logfile->print(sprintf("$logtime $level, $tid$format\n", @args));
91	} else {
92	    printf STDERR ("$logtime $level, $tid$format\n", @args);
93	}
94    } elsif (my $eventLog = $self->{'eventLog'}) {
95	my($type, $category);
96	if ($level eq 'debug') {
97	    $type = Win32::EventLog::EVENTLOG_INFORMATION_TYPE();
98	    $category = 10;
99	} elsif ($level eq 'notice') {
100	    $type = Win32::EventLog::EVENTLOG_INFORMATION_TYPE();
101	    $category = 20;
102	} else {
103	    $type = Win32::EventLog::EVENTLOG_ERROR_TYPE();
104	    $category = 50;
105	}
106	$eventLog->Report({
107	    'Category' => $category,
108	    'EventType' => $type,
109	    'EventID' => ++$self->{'eventId'},
110	    'Strings' => sprintf($format, @args),
111	    'Data' => $tid
112	    });
113    } else {
114	&Sys::Syslog::syslog($level, "$tid$format", @args);
115    }
116}
117
118sub Debug ($$;@) {
119    my $self = shift;
120    if (!ref($self)  ||  $self->{'debug'}) {
121	my $fmt = shift;
122	$self->Log('debug', $fmt, @_);
123    }
124}
125
126sub Error ($$;@) {
127    my $self = shift; my $fmt = shift;
128    $self->Log('err', $fmt, @_);
129}
130
131sub Fatal ($$;@) {
132    my $self = shift; my $fmt = shift;
133    my $msg = sprintf($fmt, @_);
134    $self->Log('err', $msg);
135    my($package, $filename, $line) = caller();
136    die "$msg at $filename line $line.";
137}
138
139sub LogTime { scalar(localtime) }
140
141
1421;
143
144__END__
145
146=head1 NAME
147
148Net::Daemon::Log - Utility functions for logging
149
150
151=head1 SYNOPSIS
152
153  # Choose logging method: syslog or Win32::EventLog
154  $self->{'facility'} = 'mail'; # Default: Daemon
155  $self->{'logfile'} = undef;   # Default
156
157  # Choose logging method: stderr
158  $self->{'logfile'} = 1;
159
160  # Choose logging method: IO handle
161  my $file = IO::File->new("my.log", "a");
162  $self->{'logfile'} = $file;
163
164
165  # Debugging messages (equivalent):
166  $self->Log('debug', "This is a debugging message");
167  $self->Debug("This is a debugging message");
168
169  # Error messages (equivalent):
170  $self->Log('err', "This is an error message");
171  $self->Error("This is an error message");
172
173  # Fatal error messages (implies 'die')
174  $self->Fatal("This is a fatal error message");
175
176
177=head1 WARNING
178
179THIS IS ALPHA SOFTWARE. It is *only* 'Alpha' because the interface (API)
180is not finalised. The Alpha status does not reflect code quality or
181stability.
182
183
184=head1 DESCRIPTION
185
186Net::Daemon::Log is a utility class for portable logging messages.
187By default it uses syslog (Unix) or Win32::EventLog (Windows), but
188logging messages can also be redirected to stderr or a log file.
189
190
191=head2 Generic Logging
192
193    $self->Log($level, $msg, @args);
194
195This is the generic interface. The logging level is in syslog style,
196thus one of the words 'debug', 'info', 'notice', 'err' or 'crit'.
197You'll rarely need info and notice and I can hardly imagine a reason
198for crit (critical). In 95% of all cases debug and err will be
199sufficient.
200
201The logging string $msg is a format string similar to printf.
202
203
204=head2 Utility methods
205
206    $self->Debug($msg, @args);
207    $self->Error($msg, @args);
208    $self->Fatal($msg, @args);
209
210These are replacements for logging with levels debug and err. The difference
211between the latter two is that Fatal includes throwing a Perl exception.
212
213
214=head2 Chossing a logging target
215
216By default logging will happen to syslog (Unix) or EventLog (Windows).
217However you may choose logging to stderr by setting
218
219    $self->{'logfile'} = 1;
220
221This is required if neither of syslog and EventLog is available. An
222alternative option is setting
223
224    $self->{'logfile'} = $handle;
225
226where $handle is any object supporting a I<print> method, for example
227an IO::Handle object. Usually the logging target is choosen as soon
228as you call $self->Log() the first time. However, you may force
229choosing the target by doing a
230
231    $self->OpenLog();
232
233before calling Log the first time.
234
235
236=head1 MULTITHREADING
237
238The Multithreading capabitities of this class are depending heavily
239on the underlying classes Sys::Syslog, Win32::EventLog or IO::Handle.
240If they are thread safe, you can well assume that this package is
241too. (The exception being that you should better call
242$self->OpenLog() before threading.)
243
244
245=head1 AUTHOR AND COPYRIGHT
246
247  Net::Daemon is Copyright (C) 1998, Jochen Wiedmann
248                                     Am Eisteich 9
249                                     72555 Metzingen
250                                     Germany
251
252                                     Phone: +49 7123 14887
253                                     Email: joe@ispsoft.de
254
255  All rights reserved.
256
257  You may distribute this package under the terms of either the GNU
258  General Public License or the Artistic License, as specified in the
259  Perl README file.
260
261
262=head1 SEE ALSO
263
264L<Net::Daemon(3)>, L<Sys::Syslog(3)>, L<Win32::EventLog(3)>,
265L<IO::Handle(3)>
266
267=cut
268
269