1 # Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
3 # Permission to use, copy, modify, and distribute this software and its
4 # documentation for any purpose and without fee is hereby granted,
5 # provided that the above copyright notice appear in all copies and that
6 # both that copyright notice and this permission notice appear in
7 # supporting documentation, and that the name of Vinay Sajip
8 # not be used in advertising or publicity pertaining to distribution
9 # of the software without specific, written prior permission.
10 # VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11 # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12 # VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 Logging package for Python. Based on PEP 282 and comments thereto in
19 comp.lang.python, and influenced by Apache's log4j system.
21 Should work under Python versions >= 1.5.2, except that source line
22 information is not available unless 'inspect' is.
24 Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
26 To use, simply 'import logging' and log away!
29 import sys
, logging
, socket
, types
, os
, string
, cPickle
, struct
, time
31 from SocketServer
import ThreadingTCPServer
, StreamRequestHandler
37 DEFAULT_TCP_LOGGING_PORT
= 9020
38 DEFAULT_UDP_LOGGING_PORT
= 9021
39 DEFAULT_HTTP_LOGGING_PORT
= 9022
40 DEFAULT_SOAP_LOGGING_PORT
= 9023
44 class RotatingFileHandler(logging
.FileHandler
):
45 def __init__(self
, filename
, mode
="a", maxBytes
=0, backupCount
=0):
47 Open the specified file and use it as the stream for logging.
49 By default, the file grows indefinitely. You can specify particular
50 values of maxBytes and backupCount to allow the file to rollover at
53 Rollover occurs whenever the current log file is nearly maxBytes in
54 length. If backupCount is >= 1, the system will successively create
55 new files with the same pathname as the base file, but with extensions
56 ".1", ".2" etc. appended to it. For example, with a backupCount of 5
57 and a base file name of "app.log", you would get "app.log",
58 "app.log.1", "app.log.2", ... through to "app.log.5". The file being
59 written to is always "app.log" - when it gets filled up, it is closed
60 and renamed to "app.log.1", and if files "app.log.1", "app.log.2" etc.
61 exist, then they are renamed to "app.log.2", "app.log.3" etc.
64 If maxBytes is zero, rollover never occurs.
66 logging
.FileHandler
.__init
__(self
, filename
, mode
)
67 self
.maxBytes
= maxBytes
68 self
.backupCount
= backupCount
74 Do a rollover, as described in __init__().
78 if self
.backupCount
> 0:
79 for i
in range(self
.backupCount
- 1, 0, -1):
80 sfn
= "%s.%d" % (self
.baseFilename
, i
)
81 dfn
= "%s.%d" % (self
.baseFilename
, i
+ 1)
82 if os
.path
.exists(sfn
):
83 #print "%s -> %s" % (sfn, dfn)
84 if os
.path
.exists(dfn
):
87 dfn
= self
.baseFilename
+ ".1"
88 if os
.path
.exists(dfn
):
90 os
.rename(self
.baseFilename
, dfn
)
91 #print "%s -> %s" % (self.baseFilename, dfn)
92 self
.stream
= open(self
.baseFilename
, "w")
94 def emit(self
, record
):
98 Output the record to the file, catering for rollover as described
101 if self
.maxBytes
> 0: # are we rolling over?
102 msg
= "%s\n" % self
.format(record
)
103 self
.stream
.seek(0, 2) #due to non-posix-compliant Windows feature
104 if self
.stream
.tell() + len(msg
) >= self
.maxBytes
:
106 logging
.FileHandler
.emit(self
, record
)
109 class SocketHandler(logging
.Handler
):
111 A handler class which writes logging records, in pickle format, to
112 a streaming socket. The socket is kept open across logging calls.
113 If the peer resets it, an attempt is made to reconnect on the next call.
114 Note that the very simple wire protocol used means that packet sizes
115 are expected to be encodable within 16 bits (i.e. < 32767 bytes).
118 def __init__(self
, host
, port
):
120 Initializes the handler with a specific host address and port.
122 The attribute 'closeOnError' is set to 1 - which means that if
123 a socket error occurs, the socket is silently closed and then
124 reopened on the next logging call.
126 logging
.Handler
.__init
__(self
)
130 self
.closeOnError
= 0
132 def makeSocket(self
):
134 A factory method which allows subclasses to define the precise
135 type of socket they want.
137 s
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
)
138 s
.connect((self
.host
, self
.port
))
143 Send a pickled string to the socket.
145 This function allows for partial sends which can happen when the
148 if hasattr(self
.sock
, "sendall"):
154 sent
= self
.sock
.send(s
[sentsofar
:])
155 sentsofar
= sentsofar
+ sent
158 def makePickle(self
, record
):
160 Pickles the record in binary format with a length prefix, and
161 returns it ready for transmission across the socket.
163 s
= cPickle
.dumps(record
.__dict
__, 1)
165 #slen = "%c%c" % ((n >> 8) & 0xFF, n & 0xFF)
166 slen
= struct
.pack(">L", len(s
))
169 def handleError(self
, record
):
171 Handle an error during logging.
173 An error has occurred during logging. Most likely cause -
174 connection lost. Close the socket so that we can retry on the
177 if self
.closeOnError
and self
.sock
:
179 self
.sock
= None #try to reconnect next time
181 logging
.Handler
.handleError(self
, record
)
183 def emit(self
, record
):
187 Pickles the record and writes it to the socket in binary format.
188 If there is an error with the socket, silently drop the packet.
189 If there was a problem with the socket, re-establishes the
193 s
= self
.makePickle(record
)
195 self
.sock
= self
.makeSocket()
198 self
.handleError(record
)
208 class DatagramHandler(SocketHandler
):
210 A handler class which writes logging records, in pickle format, to
211 a datagram socket. Note that the very simple wire protocol used means
212 that packet sizes are expected to be encodable within 16 bits
213 (i.e. < 32767 bytes).
216 def __init__(self
, host
, port
):
218 Initializes the handler with a specific host address and port.
220 SocketHandler
.__init
__(self
, host
, port
)
221 self
.closeOnError
= 0
223 def makeSocket(self
):
225 The factory method of SocketHandler is here overridden to create
226 a UDP socket (SOCK_DGRAM).
228 s
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
233 Send a pickled string to a socket.
235 This function no longer allows for partial sends which can happen
236 when the network is busy - UDP does not guarantee delivery and
237 can deliver packets out of sequence.
242 #addr = (self.host, self.port)
244 # sent = self.sock.sendto(s[sentsofar:], addr)
245 # sentsofar = sentsofar + sent
247 self
.sock
.sendto(s
, (self
.host
, self
.port
))
249 class SysLogHandler(logging
.Handler
):
251 A handler class which sends formatted logging records to a syslog
252 server. Based on Sam Rushing's syslog module:
253 http://www.nightmare.com/squirl/python-ext/misc/syslog.py
254 Contributed by Nicolas Untz (after which minor refactoring changes
258 # from <linux/sys/syslog.h>:
259 # ======================================================================
260 # priorities/facilities are encoded into a single 32-bit quantity, where
261 # the bottom 3 bits are the priority (0-7) and the top 28 bits are the
262 # facility (0-big number). Both the priorities and the facilities map
263 # roughly one-to-one to strings in the syslogd(8) source code. This
264 # mapping is included in this file.
266 # priorities (these are ordered)
268 LOG_EMERG
= 0 # system is unusable
269 LOG_ALERT
= 1 # action must be taken immediately
270 LOG_CRIT
= 2 # critical conditions
271 LOG_ERR
= 3 # error conditions
272 LOG_WARNING
= 4 # warning conditions
273 LOG_NOTICE
= 5 # normal but significant condition
274 LOG_INFO
= 6 # informational
275 LOG_DEBUG
= 7 # debug-level messages
278 LOG_KERN
= 0 # kernel messages
279 LOG_USER
= 1 # random user-level messages
280 LOG_MAIL
= 2 # mail system
281 LOG_DAEMON
= 3 # system daemons
282 LOG_AUTH
= 4 # security/authorization messages
283 LOG_SYSLOG
= 5 # messages generated internally by syslogd
284 LOG_LPR
= 6 # line printer subsystem
285 LOG_NEWS
= 7 # network news subsystem
286 LOG_UUCP
= 8 # UUCP subsystem
287 LOG_CRON
= 9 # clock daemon
288 LOG_AUTHPRIV
= 10 # security/authorization messages (private)
290 # other codes through 15 reserved for system use
291 LOG_LOCAL0
= 16 # reserved for local use
292 LOG_LOCAL1
= 17 # reserved for local use
293 LOG_LOCAL2
= 18 # reserved for local use
294 LOG_LOCAL3
= 19 # reserved for local use
295 LOG_LOCAL4
= 20 # reserved for local use
296 LOG_LOCAL5
= 21 # reserved for local use
297 LOG_LOCAL6
= 22 # reserved for local use
298 LOG_LOCAL7
= 23 # reserved for local use
303 "critical": LOG_CRIT
,
307 "error": LOG_ERR
, # DEPRECATED
309 "notice": LOG_NOTICE
,
310 "panic": LOG_EMERG
, # DEPRECATED
311 "warn": LOG_WARNING
, # DEPRECATED
312 "warning": LOG_WARNING
,
317 "authpriv": LOG_AUTHPRIV
,
319 "daemon": LOG_DAEMON
,
324 "security": LOG_AUTH
, # DEPRECATED
325 "syslog": LOG_SYSLOG
,
328 "local0": LOG_LOCAL0
,
329 "local1": LOG_LOCAL1
,
330 "local2": LOG_LOCAL2
,
331 "local3": LOG_LOCAL3
,
332 "local4": LOG_LOCAL4
,
333 "local5": LOG_LOCAL5
,
334 "local6": LOG_LOCAL6
,
335 "local7": LOG_LOCAL7
,
338 def __init__(self
, address
=('localhost', SYSLOG_UDP_PORT
), facility
=LOG_USER
):
340 Initialize a handler.
342 If address is specified as a string, UNIX socket is used.
343 If facility is not specified, LOG_USER is used.
345 logging
.Handler
.__init
__(self
)
347 self
.address
= address
348 self
.facility
= facility
349 if type(address
) == types
.StringType
:
350 self
.socket
= socket
.socket(socket
.AF_UNIX
, socket
.SOCK_DGRAM
)
351 # syslog may require either DGRAM or STREAM sockets
353 self
.socket
.connect(address
)
356 self
.socket
= socket
.socket(socket
.AF_UNIX
, socket
.SOCK_STREAM
)
357 self
.socket
.connect(address
)
360 self
.socket
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
363 self
.formatter
= None
365 # curious: when talking to the unix-domain '/dev/log' socket, a
366 # zero-terminator seems to be required. this string is placed
367 # into a class variable so that it can be overridden if
369 log_format_string
= '<%d>%s\000'
371 def encodePriority (self
, facility
, priority
):
373 Encode the facility and priority. You can pass in strings or
374 integers - if strings are passed, the facility_names and
375 priority_names mapping dictionaries are used to convert them to
378 if type(facility
) == types
.StringType
:
379 facility
= self
.facility_names
[facility
]
380 if type(priority
) == types
.StringType
:
381 priority
= self
.priority_names
[priority
]
382 return (facility
<< 3) | priority
391 def emit(self
, record
):
395 The record is formatted, and then sent to the syslog server. If
396 exception information is present, it is NOT sent to the server.
398 msg
= self
.format(record
)
400 We need to convert record level to lowercase, maybe this will
401 change in the future.
403 msg
= self
.log_format_string
% (
404 self
.encodePriority(self
.facility
,
405 string
.lower(record
.levelname
)),
409 self
.socket
.send(msg
)
411 self
.socket
.sendto(msg
, self
.address
)
413 self
.handleError(record
)
415 class SMTPHandler(logging
.Handler
):
417 A handler class which sends an SMTP email for each logging event.
419 def __init__(self
, mailhost
, fromaddr
, toaddrs
, subject
):
421 Initialize the handler.
423 Initialize the instance with the from and to addresses and subject
424 line of the email. To specify a non-standard SMTP port, use the
425 (host, port) tuple format for the mailhost argument.
427 logging
.Handler
.__init
__(self
)
428 if type(mailhost
) == types
.TupleType
:
429 host
, port
= mailhost
433 self
.mailhost
= mailhost
435 self
.fromaddr
= fromaddr
436 if type(toaddrs
) == types
.StringType
:
438 self
.toaddrs
= toaddrs
439 self
.subject
= subject
441 def getSubject(self
, record
):
443 Determine the subject for the email.
445 If you want to specify a subject line which is record-dependent,
446 override this method.
450 weekdayname
= ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
453 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
454 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
457 """Return the current date and time formatted for a MIME header."""
458 year
, month
, day
, hh
, mm
, ss
, wd
, y
, z
= time
.gmtime(time
.time())
459 s
= "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
460 self
.weekdayname
[wd
],
461 day
, self
.monthname
[month
], year
,
465 def emit(self
, record
):
469 Format the record and send it to the specified addressees.
475 port
= smtplib
.SMTP_PORT
476 smtp
= smtplib
.SMTP(self
.mailhost
, port
)
477 msg
= self
.format(record
)
478 msg
= "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
480 string
.join(self
.toaddrs
, ","),
481 self
.getSubject(record
),
482 self
.date_time(), msg
)
483 smtp
.sendmail(self
.fromaddr
, self
.toaddrs
, msg
)
486 self
.handleError(record
)
488 class NTEventLogHandler(logging
.Handler
):
490 A handler class which sends events to the NT Event Log. Adds a
491 registry entry for the specified application name. If no dllname is
492 provided, win32service.pyd (which contains some basic message
493 placeholders) is used. Note that use of these placeholders will make
494 your event logs big, as the entire message source is held in the log.
495 If you want slimmer logs, you have to pass in the name of your own DLL
496 which contains the message definitions you want to use in the event log.
498 def __init__(self
, appname
, dllname
=None, logtype
="Application"):
499 logging
.Handler
.__init
__(self
)
501 import win32evtlogutil
, win32evtlog
502 self
.appname
= appname
503 self
._welu
= win32evtlogutil
505 dllname
= os
.path
.split(self
._welu
.__file
__)
506 dllname
= os
.path
.split(dllname
[0])
507 dllname
= os
.path
.join(dllname
[0], r
'win32service.pyd')
508 self
.dllname
= dllname
509 self
.logtype
= logtype
510 self
._welu
.AddSourceToRegistry(appname
, dllname
, logtype
)
511 self
.deftype
= win32evtlog
.EVENTLOG_ERROR_TYPE
513 logging
.DEBUG
: win32evtlog
.EVENTLOG_INFORMATION_TYPE
,
514 logging
.INFO
: win32evtlog
.EVENTLOG_INFORMATION_TYPE
,
515 logging
.WARNING
: win32evtlog
.EVENTLOG_WARNING_TYPE
,
516 logging
.ERROR
: win32evtlog
.EVENTLOG_ERROR_TYPE
,
517 logging
.CRITICAL
: win32evtlog
.EVENTLOG_ERROR_TYPE
,
520 print "The Python Win32 extensions for NT (service, event "\
521 "logging) appear not to be available."
524 def getMessageID(self
, record
):
526 Return the message ID for the event record. If you are using your
527 own messages, you could do this by having the msg passed to the
528 logger being an ID rather than a formatting string. Then, in here,
529 you could use a dictionary lookup to get the message ID. This
530 version returns 1, which is the base message ID in win32service.pyd.
534 def getEventCategory(self
, record
):
536 Return the event category for the record.
538 Override this if you want to specify your own categories. This version
543 def getEventType(self
, record
):
545 Return the event type for the record.
547 Override this if you want to specify your own types. This version does
548 a mapping using the handler's typemap attribute, which is set up in
549 __init__() to a dictionary which contains mappings for DEBUG, INFO,
550 WARNING, ERROR and CRITICAL. If you are using your own levels you will
551 either need to override this method or place a suitable dictionary in
552 the handler's typemap attribute.
554 return self
.typemap
.get(record
.levelno
, self
.deftype
)
556 def emit(self
, record
):
560 Determine the message ID, event category and event type. Then
561 log the message in the NT event log.
565 id = self
.getMessageID(record
)
566 cat
= self
.getEventCategory(record
)
567 type = self
.getEventType(record
)
568 msg
= self
.format(record
)
569 self
._welu
.ReportEvent(self
.appname
, id, cat
, type, [msg
])
571 self
.handleError(record
)
575 Clean up this handler.
577 You can remove the application name from the registry as a
578 source of event log entries. However, if you do this, you will
579 not be able to see the events as you intended in the Event Log
580 Viewer - it needs to be able to access the registry to get the
583 #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype)
586 class HTTPHandler(logging
.Handler
):
588 A class which sends records to a Web server, using either GET or
591 def __init__(self
, host
, url
, method
="GET"):
593 Initialize the instance with the host, the request URL, and the method
596 logging
.Handler
.__init
__(self
)
597 method
= string
.upper(method
)
598 if method
not in ["GET", "POST"]:
599 raise ValueError, "method must be GET or POST"
604 def mapLogRecord(self
, record
):
606 Default implementation of mapping the log record into a dict
607 that is send as the CGI data. Overwrite in your class.
608 Contributed by Franz Glasner.
610 return record
.__dict
__
612 def emit(self
, record
):
616 Send the record to the Web server as an URL-encoded dictionary
619 import httplib
, urllib
620 h
= httplib
.HTTP(self
.host
)
622 data
= urllib
.urlencode(self
.mapLogRecord(record
))
623 if self
.method
== "GET":
624 if (string
.find(url
, '?') >= 0):
628 url
= url
+ "%c%s" % (sep
, data
)
629 h
.putrequest(self
.method
, url
)
630 if self
.method
== "POST":
631 h
.putheader("Content-length", str(len(data
)))
633 if self
.method
== "POST":
635 h
.getreply() #can't do anything with the result
637 self
.handleError(record
)
639 class BufferingHandler(logging
.Handler
):
641 A handler class which buffers logging records in memory. Whenever each
642 record is added to the buffer, a check is made to see if the buffer should
643 be flushed. If it should, then flush() is expected to do what's needed.
645 def __init__(self
, capacity
):
647 Initialize the handler with the buffer size.
649 logging
.Handler
.__init
__(self
)
650 self
.capacity
= capacity
653 def shouldFlush(self
, record
):
655 Should the handler flush its buffer?
657 Returns true if the buffer is up to capacity. This method can be
658 overridden to implement custom flushing strategies.
660 return (len(self
.buffer) >= self
.capacity
)
662 def emit(self
, record
):
666 Append the record. If shouldFlush() tells us to, call flush() to process
669 self
.buffer.append(record
)
670 if self
.shouldFlush(record
):
675 Override to implement custom flushing behaviour.
677 This version just zaps the buffer to empty.
681 class MemoryHandler(BufferingHandler
):
683 A handler class which buffers logging records in memory, periodically
684 flushing them to a target handler. Flushing occurs whenever the buffer
685 is full, or when an event of a certain severity or greater is seen.
687 def __init__(self
, capacity
, flushLevel
=logging
.ERROR
, target
=None):
689 Initialize the handler with the buffer size, the level at which
690 flushing should occur and an optional target.
692 Note that without a target being set either here or via setTarget(),
693 a MemoryHandler is no use to anyone!
695 BufferingHandler
.__init
__(self
, capacity
)
696 self
.flushLevel
= flushLevel
699 def shouldFlush(self
, record
):
701 Check for buffer full or a record at the flushLevel or higher.
703 return (len(self
.buffer) >= self
.capacity
) or \
704 (record
.levelno
>= self
.flushLevel
)
706 def setTarget(self
, target
):
708 Set the target handler for this handler.
714 For a MemoryHandler, flushing means just sending the buffered
715 records to the target, if there is one. Override if you want
719 for record
in self
.buffer:
720 self
.target
.handle(record
)
725 Flush, set the target to None and lose the buffer.