Update version number and release date.
[python/dscho.git] / Lib / logging / handlers.py
blob4a597a1627f0b88b120e56302f9fa77d02f13a51
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.
17 """
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!
27 """
29 import sys, logging, socket, types, os, string, cPickle, struct, time
31 from SocketServer import ThreadingTCPServer, StreamRequestHandler
34 # Some constants...
37 DEFAULT_TCP_LOGGING_PORT = 9020
38 DEFAULT_UDP_LOGGING_PORT = 9021
39 DEFAULT_HTTP_LOGGING_PORT = 9022
40 DEFAULT_SOAP_LOGGING_PORT = 9023
41 SYSLOG_UDP_PORT = 514
44 class RotatingFileHandler(logging.FileHandler):
45 def __init__(self, filename, mode="a", maxBytes=0, backupCount=0):
46 """
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
51 a predetermined size.
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.
62 respectively.
64 If maxBytes is zero, rollover never occurs.
65 """
66 logging.FileHandler.__init__(self, filename, mode)
67 self.maxBytes = maxBytes
68 self.backupCount = backupCount
69 if maxBytes > 0:
70 self.mode = "a"
72 def doRollover(self):
73 """
74 Do a rollover, as described in __init__().
75 """
77 self.stream.close()
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):
85 os.remove(dfn)
86 os.rename(sfn, dfn)
87 dfn = self.baseFilename + ".1"
88 if os.path.exists(dfn):
89 os.remove(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):
95 """
96 Emit a record.
98 Output the record to the file, catering for rollover as described
99 in setRollover().
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:
105 self.doRollover()
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)
127 self.host = host
128 self.port = port
129 self.sock = None
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))
139 return s
141 def send(self, s):
143 Send a pickled string to the socket.
145 This function allows for partial sends which can happen when the
146 network is busy.
148 if hasattr(self.sock, "sendall"):
149 self.sock.sendall(s)
150 else:
151 sentsofar = 0
152 left = len(s)
153 while left > 0:
154 sent = self.sock.send(s[sentsofar:])
155 sentsofar = sentsofar + sent
156 left = left - 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)
164 #n = len(s)
165 #slen = "%c%c" % ((n >> 8) & 0xFF, n & 0xFF)
166 slen = struct.pack(">L", len(s))
167 return slen + 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
175 next event.
177 if self.closeOnError and self.sock:
178 self.sock.close()
179 self.sock = None #try to reconnect next time
180 else:
181 logging.Handler.handleError(self, record)
183 def emit(self, record):
185 Emit a 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
190 socket.
192 try:
193 s = self.makePickle(record)
194 if not self.sock:
195 self.sock = self.makeSocket()
196 self.send(s)
197 except:
198 self.handleError(record)
200 def close(self):
202 Closes the socket.
204 if self.sock:
205 self.sock.close()
206 self.sock = None
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)
229 return s
231 def send(self, s):
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.
239 #old code
240 #sentsofar = 0
241 #left = len(s)
242 #addr = (self.host, self.port)
243 #while left > 0:
244 # sent = self.sock.sendto(s[sentsofar:], addr)
245 # sentsofar = sentsofar + sent
246 # left = left - 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
255 have been made).
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
277 # facility codes
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
300 priority_names = {
301 "alert": LOG_ALERT,
302 "crit": LOG_CRIT,
303 "critical": LOG_CRIT,
304 "debug": LOG_DEBUG,
305 "emerg": LOG_EMERG,
306 "err": LOG_ERR,
307 "error": LOG_ERR, # DEPRECATED
308 "info": LOG_INFO,
309 "notice": LOG_NOTICE,
310 "panic": LOG_EMERG, # DEPRECATED
311 "warn": LOG_WARNING, # DEPRECATED
312 "warning": LOG_WARNING,
315 facility_names = {
316 "auth": LOG_AUTH,
317 "authpriv": LOG_AUTHPRIV,
318 "cron": LOG_CRON,
319 "daemon": LOG_DAEMON,
320 "kern": LOG_KERN,
321 "lpr": LOG_LPR,
322 "mail": LOG_MAIL,
323 "news": LOG_NEWS,
324 "security": LOG_AUTH, # DEPRECATED
325 "syslog": LOG_SYSLOG,
326 "user": LOG_USER,
327 "uucp": LOG_UUCP,
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
352 try:
353 self.socket.connect(address)
354 except socket.error:
355 self.socket.close()
356 self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
357 self.socket.connect(address)
358 self.unixsocket = 1
359 else:
360 self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
361 self.unixsocket = 0
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
368 # necessary.
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
376 integers.
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
384 def close (self):
386 Closes the socket.
388 if self.unixsocket:
389 self.socket.close()
391 def emit(self, record):
393 Emit a 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)),
406 msg)
407 try:
408 if self.unixsocket:
409 self.socket.send(msg)
410 else:
411 self.socket.sendto(msg, self.address)
412 except:
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
430 self.mailhost = host
431 self.mailport = port
432 else:
433 self.mailhost = mailhost
434 self.mailport = None
435 self.fromaddr = fromaddr
436 if type(toaddrs) == types.StringType:
437 toaddrs = [toaddrs]
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.
448 return self.subject
450 weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
452 monthname = [None,
453 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
454 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
456 def date_time(self):
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,
462 hh, mm, ss)
463 return s
465 def emit(self, record):
467 Emit a record.
469 Format the record and send it to the specified addressees.
471 try:
472 import smtplib
473 port = self.mailport
474 if not port:
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" % (
479 self.fromaddr,
480 string.join(self.toaddrs, ","),
481 self.getSubject(record),
482 self.date_time(), msg)
483 smtp.sendmail(self.fromaddr, self.toaddrs, msg)
484 smtp.quit()
485 except:
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)
500 try:
501 import win32evtlogutil, win32evtlog
502 self.appname = appname
503 self._welu = win32evtlogutil
504 if not dllname:
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
512 self.typemap = {
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,
519 except ImportError:
520 print "The Python Win32 extensions for NT (service, event "\
521 "logging) appear not to be available."
522 self._welu = None
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.
532 return 1
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
539 returns 0.
541 return 0
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):
558 Emit a record.
560 Determine the message ID, event category and event type. Then
561 log the message in the NT event log.
563 if self._welu:
564 try:
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])
570 except:
571 self.handleError(record)
573 def close(self):
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
581 DLL name.
583 #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype)
584 pass
586 class HTTPHandler(logging.Handler):
588 A class which sends records to a Web server, using either GET or
589 POST semantics.
591 def __init__(self, host, url, method="GET"):
593 Initialize the instance with the host, the request URL, and the method
594 ("GET" or "POST")
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"
600 self.host = host
601 self.url = url
602 self.method = method
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):
614 Emit a record.
616 Send the record to the Web server as an URL-encoded dictionary
618 try:
619 import httplib, urllib
620 h = httplib.HTTP(self.host)
621 url = self.url
622 data = urllib.urlencode(self.mapLogRecord(record))
623 if self.method == "GET":
624 if (string.find(url, '?') >= 0):
625 sep = '&'
626 else:
627 sep = '?'
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)))
632 h.endheaders()
633 if self.method == "POST":
634 h.send(data)
635 h.getreply() #can't do anything with the result
636 except:
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
651 self.buffer = []
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):
664 Emit a record.
666 Append the record. If shouldFlush() tells us to, call flush() to process
667 the buffer.
669 self.buffer.append(record)
670 if self.shouldFlush(record):
671 self.flush()
673 def flush(self):
675 Override to implement custom flushing behaviour.
677 This version just zaps the buffer to empty.
679 self.buffer = []
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
697 self.target = target
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.
710 self.target = target
712 def flush(self):
714 For a MemoryHandler, flushing means just sending the buffered
715 records to the target, if there is one. Override if you want
716 different behaviour.
718 if self.target:
719 for record in self.buffer:
720 self.target.handle(record)
721 self.buffer = []
723 def close(self):
725 Flush, set the target to None and lose the buffer.
727 self.flush()
728 self.target = None
729 self.buffer = []