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 The pickle which is sent is that of the LogRecord's attribute dictionary
115 (__dict__), so that the receiver does not need to have the logging module
116 installed in order to process the logging event.
118 To unpickle the record at the receiving end into a LogRecord, use the
119 makeLogRecord function.
122 def __init__(self, host, port):
124 Initializes the handler with a specific host address and port.
126 The attribute 'closeOnError' is set to 1 - which means that if
127 a socket error occurs, the socket is silently closed and then
128 reopened on the next logging call.
130 logging.Handler.__init__(self)
134 self.closeOnError = 0
136 def makeSocket(self):
138 A factory method which allows subclasses to define the precise
139 type of socket they want.
141 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
142 s.connect((self.host, self.port))
147 Send a pickled string to the socket.
149 This function allows for partial sends which can happen when the
152 if hasattr(self.sock, "sendall"):
158 sent = self.sock.send(s[sentsofar:])
159 sentsofar = sentsofar + sent
162 def makePickle(self, record):
164 Pickles the record in binary format with a length prefix, and
165 returns it ready for transmission across the socket.
167 s = cPickle.dumps(record.__dict__, 1)
169 #slen = "%c%c" % ((n >> 8) & 0xFF, n & 0xFF)
170 slen = struct.pack(">L", len(s))
173 def handleError(self, record):
175 Handle an error during logging.
177 An error has occurred during logging. Most likely cause -
178 connection lost. Close the socket so that we can retry on the
181 if self.closeOnError and self.sock:
183 self.sock = None #try to reconnect next time
185 logging.Handler.handleError(self, record)
187 def emit(self, record):
191 Pickles the record and writes it to the socket in binary format.
192 If there is an error with the socket, silently drop the packet.
193 If there was a problem with the socket, re-establishes the
197 s = self.makePickle(record)
199 self.sock = self.makeSocket()
202 self.handleError(record)
212 class DatagramHandler(SocketHandler):
214 A handler class which writes logging records, in pickle format, to
215 a datagram socket. The pickle which is sent is that of the LogRecord's
216 attribute dictionary (__dict__), so that the receiver does not need to
217 have the logging module installed in order to process the logging event.
219 To unpickle the record at the receiving end into a LogRecord, use the
220 makeLogRecord function.
223 def __init__(self, host, port):
225 Initializes the handler with a specific host address and port.
227 SocketHandler.__init__(self, host, port)
228 self.closeOnError = 0
230 def makeSocket(self):
232 The factory method of SocketHandler is here overridden to create
233 a UDP socket (SOCK_DGRAM).
235 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
240 Send a pickled string to a socket.
242 This function no longer allows for partial sends which can happen
243 when the network is busy - UDP does not guarantee delivery and
244 can deliver packets out of sequence.
246 self.sock.sendto(s, (self.host, self.port))
248 class SysLogHandler(logging.Handler):
250 A handler class which sends formatted logging records to a syslog
251 server. Based on Sam Rushing's syslog module:
252 http://www.nightmare.com/squirl/python-ext/misc/syslog.py
253 Contributed by Nicolas Untz (after which minor refactoring changes
257 # from <linux/sys/syslog.h>:
258 # ======================================================================
259 # priorities/facilities are encoded into a single 32-bit quantity, where
260 # the bottom 3 bits are the priority (0-7) and the top 28 bits are the
261 # facility (0-big number). Both the priorities and the facilities map
262 # roughly one-to-one to strings in the syslogd(8) source code. This
263 # mapping is included in this file.
265 # priorities (these are ordered)
267 LOG_EMERG = 0 # system is unusable
268 LOG_ALERT = 1 # action must be taken immediately
269 LOG_CRIT = 2 # critical conditions
270 LOG_ERR = 3 # error conditions
271 LOG_WARNING = 4 # warning conditions
272 LOG_NOTICE = 5 # normal but significant condition
273 LOG_INFO = 6 # informational
274 LOG_DEBUG = 7 # debug-level messages
277 LOG_KERN = 0 # kernel messages
278 LOG_USER = 1 # random user-level messages
279 LOG_MAIL = 2 # mail system
280 LOG_DAEMON = 3 # system daemons
281 LOG_AUTH = 4 # security/authorization messages
282 LOG_SYSLOG = 5 # messages generated internally by syslogd
283 LOG_LPR = 6 # line printer subsystem
284 LOG_NEWS = 7 # network news subsystem
285 LOG_UUCP = 8 # UUCP subsystem
286 LOG_CRON = 9 # clock daemon
287 LOG_AUTHPRIV = 10 # security/authorization messages (private)
289 # other codes through 15 reserved for system use
290 LOG_LOCAL0 = 16 # reserved for local use
291 LOG_LOCAL1 = 17 # reserved for local use
292 LOG_LOCAL2 = 18 # reserved for local use
293 LOG_LOCAL3 = 19 # reserved for local use
294 LOG_LOCAL4 = 20 # reserved for local use
295 LOG_LOCAL5 = 21 # reserved for local use
296 LOG_LOCAL6 = 22 # reserved for local use
297 LOG_LOCAL7 = 23 # reserved for local use
302 "critical": LOG_CRIT,
306 "error": LOG_ERR, # DEPRECATED
308 "notice": LOG_NOTICE,
309 "panic": LOG_EMERG, # DEPRECATED
310 "warn": LOG_WARNING, # DEPRECATED
311 "warning": LOG_WARNING,
316 "authpriv": LOG_AUTHPRIV,
318 "daemon": LOG_DAEMON,
323 "security": LOG_AUTH, # DEPRECATED
324 "syslog": LOG_SYSLOG,
327 "local0": LOG_LOCAL0,
328 "local1": LOG_LOCAL1,
329 "local2": LOG_LOCAL2,
330 "local3": LOG_LOCAL3,
331 "local4": LOG_LOCAL4,
332 "local5": LOG_LOCAL5,
333 "local6": LOG_LOCAL6,
334 "local7": LOG_LOCAL7,
337 def __init__(self, address=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER):
339 Initialize a handler.
341 If address is specified as a string, UNIX socket is used.
342 If facility is not specified, LOG_USER is used.
344 logging.Handler.__init__(self)
346 self.address = address
347 self.facility = facility
348 if type(address) == types.StringType:
349 self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
350 # syslog may require either DGRAM or STREAM sockets
352 self.socket.connect(address)
355 self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
356 self.socket.connect(address)
359 self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
362 self.formatter = None
364 # curious: when talking to the unix-domain '/dev/log' socket, a
365 # zero-terminator seems to be required. this string is placed
366 # into a class variable so that it can be overridden if
368 log_format_string = '<%d>%s\000'
370 def encodePriority (self, facility, priority):
372 Encode the facility and priority. You can pass in strings or
373 integers - if strings are passed, the facility_names and
374 priority_names mapping dictionaries are used to convert them to
377 if type(facility) == types.StringType:
378 facility = self.facility_names[facility]
379 if type(priority) == types.StringType:
380 priority = self.priority_names[priority]
381 return (facility << 3) | priority
390 def emit(self, record):
394 The record is formatted, and then sent to the syslog server. If
395 exception information is present, it is NOT sent to the server.
397 msg = self.format(record)
399 We need to convert record level to lowercase, maybe this will
400 change in the future.
402 msg = self.log_format_string % (
403 self.encodePriority(self.facility,
404 string.lower(record.levelname)),
408 self.socket.send(msg)
410 self.socket.sendto(msg, self.address)
412 self.handleError(record)
414 class SMTPHandler(logging.Handler):
416 A handler class which sends an SMTP email for each logging event.
418 def __init__(self, mailhost, fromaddr, toaddrs, subject):
420 Initialize the handler.
422 Initialize the instance with the from and to addresses and subject
423 line of the email. To specify a non-standard SMTP port, use the
424 (host, port) tuple format for the mailhost argument.
426 logging.Handler.__init__(self)
427 if type(mailhost) == types.TupleType:
428 host, port = mailhost
432 self.mailhost = mailhost
434 self.fromaddr = fromaddr
435 if type(toaddrs) == types.StringType:
437 self.toaddrs = toaddrs
438 self.subject = subject
440 def getSubject(self, record):
442 Determine the subject for the email.
444 If you want to specify a subject line which is record-dependent,
445 override this method.
449 weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
452 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
453 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
456 """Return the current date and time formatted for a MIME header."""
457 year, month, day, hh, mm, ss, wd, y, z = time.gmtime(time.time())
458 s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
459 self.weekdayname[wd],
460 day, self.monthname[month], year,
464 def emit(self, record):
468 Format the record and send it to the specified addressees.
474 port = smtplib.SMTP_PORT
475 smtp = smtplib.SMTP(self.mailhost, port)
476 msg = self.format(record)
477 msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
479 string.join(self.toaddrs, ","),
480 self.getSubject(record),
481 self.date_time(), msg)
482 smtp.sendmail(self.fromaddr, self.toaddrs, msg)
485 self.handleError(record)
487 class NTEventLogHandler(logging.Handler):
489 A handler class which sends events to the NT Event Log. Adds a
490 registry entry for the specified application name. If no dllname is
491 provided, win32service.pyd (which contains some basic message
492 placeholders) is used. Note that use of these placeholders will make
493 your event logs big, as the entire message source is held in the log.
494 If you want slimmer logs, you have to pass in the name of your own DLL
495 which contains the message definitions you want to use in the event log.
497 def __init__(self, appname, dllname=None, logtype="Application"):
498 logging.Handler.__init__(self)
500 import win32evtlogutil, win32evtlog
501 self.appname = appname
502 self._welu = win32evtlogutil
504 dllname = os.path.split(self._welu.__file__)
505 dllname = os.path.split(dllname[0])
506 dllname = os.path.join(dllname[0], r'win32service.pyd')
507 self.dllname = dllname
508 self.logtype = logtype
509 self._welu.AddSourceToRegistry(appname, dllname, logtype)
510 self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE
512 logging.DEBUG : win32evtlog.EVENTLOG_INFORMATION_TYPE,
513 logging.INFO : win32evtlog.EVENTLOG_INFORMATION_TYPE,
514 logging.WARNING : win32evtlog.EVENTLOG_WARNING_TYPE,
515 logging.ERROR : win32evtlog.EVENTLOG_ERROR_TYPE,
516 logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
519 print "The Python Win32 extensions for NT (service, event "\
520 "logging) appear not to be available."
523 def getMessageID(self, record):
525 Return the message ID for the event record. If you are using your
526 own messages, you could do this by having the msg passed to the
527 logger being an ID rather than a formatting string. Then, in here,
528 you could use a dictionary lookup to get the message ID. This
529 version returns 1, which is the base message ID in win32service.pyd.
533 def getEventCategory(self, record):
535 Return the event category for the record.
537 Override this if you want to specify your own categories. This version
542 def getEventType(self, record):
544 Return the event type for the record.
546 Override this if you want to specify your own types. This version does
547 a mapping using the handler's typemap attribute, which is set up in
548 __init__() to a dictionary which contains mappings for DEBUG, INFO,
549 WARNING, ERROR and CRITICAL. If you are using your own levels you will
550 either need to override this method or place a suitable dictionary in
551 the handler's typemap attribute.
553 return self.typemap.get(record.levelno, self.deftype)
555 def emit(self, record):
559 Determine the message ID, event category and event type. Then
560 log the message in the NT event log.
564 id = self.getMessageID(record)
565 cat = self.getEventCategory(record)
566 type = self.getEventType(record)
567 msg = self.format(record)
568 self._welu.ReportEvent(self.appname, id, cat, type, [msg])
570 self.handleError(record)
574 Clean up this handler.
576 You can remove the application name from the registry as a
577 source of event log entries. However, if you do this, you will
578 not be able to see the events as you intended in the Event Log
579 Viewer - it needs to be able to access the registry to get the
582 #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype)
585 class HTTPHandler(logging.Handler):
587 A class which sends records to a Web server, using either GET or
590 def __init__(self, host, url, method="GET"):
592 Initialize the instance with the host, the request URL, and the method
595 logging.Handler.__init__(self)
596 method = string.upper(method)
597 if method not in ["GET", "POST"]:
598 raise ValueError, "method must be GET or POST"
603 def mapLogRecord(self, record):
605 Default implementation of mapping the log record into a dict
606 that is send as the CGI data. Overwrite in your class.
607 Contributed by Franz Glasner.
609 return record.__dict__
611 def emit(self, record):
615 Send the record to the Web server as an URL-encoded dictionary
618 import httplib, urllib
619 h = httplib.HTTP(self.host)
621 data = urllib.urlencode(self.mapLogRecord(record))
622 if self.method == "GET":
623 if (string.find(url, '?') >= 0):
627 url = url + "%c%s" % (sep, data)
628 h.putrequest(self.method, url)
629 if self.method == "POST":
630 h.putheader("Content-length", str(len(data)))
632 if self.method == "POST":
634 h.getreply() #can't do anything with the result
636 self.handleError(record)
638 class BufferingHandler(logging.Handler):
640 A handler class which buffers logging records in memory. Whenever each
641 record is added to the buffer, a check is made to see if the buffer should
642 be flushed. If it should, then flush() is expected to do what's needed.
644 def __init__(self, capacity):
646 Initialize the handler with the buffer size.
648 logging.Handler.__init__(self)
649 self.capacity = capacity
652 def shouldFlush(self, record):
654 Should the handler flush its buffer?
656 Returns true if the buffer is up to capacity. This method can be
657 overridden to implement custom flushing strategies.
659 return (len(self.buffer) >= self.capacity)
661 def emit(self, record):
665 Append the record. If shouldFlush() tells us to, call flush() to process
668 self.buffer.append(record)
669 if self.shouldFlush(record):
674 Override to implement custom flushing behaviour.
676 This version just zaps the buffer to empty.
680 class MemoryHandler(BufferingHandler):
682 A handler class which buffers logging records in memory, periodically
683 flushing them to a target handler. Flushing occurs whenever the buffer
684 is full, or when an event of a certain severity or greater is seen.
686 def __init__(self, capacity, flushLevel=logging.ERROR, target=None):
688 Initialize the handler with the buffer size, the level at which
689 flushing should occur and an optional target.
691 Note that without a target being set either here or via setTarget(),
692 a MemoryHandler is no use to anyone!
694 BufferingHandler.__init__(self, capacity)
695 self.flushLevel = flushLevel
698 def shouldFlush(self, record):
700 Check for buffer full or a record at the flushLevel or higher.
702 return (len(self.buffer) >= self.capacity) or \
703 (record.levelno >= self.flushLevel)
705 def setTarget(self, target):
707 Set the target handler for this handler.
713 For a MemoryHandler, flushing means just sending the buffered
714 records to the target, if there is one. Override if you want
718 for record in self.buffer:
719 self.target.handle(record)
724 Flush, set the target to None and lose the buffer.