PyXR

c:\python24\lib \ logging \ handlers.py



0001 # Copyright 2001-2004 by Vinay Sajip. All Rights Reserved.
0002 #
0003 # Permission to use, copy, modify, and distribute this software and its
0004 # documentation for any purpose and without fee is hereby granted,
0005 # provided that the above copyright notice appear in all copies and that
0006 # both that copyright notice and this permission notice appear in
0007 # supporting documentation, and that the name of Vinay Sajip
0008 # not be used in advertising or publicity pertaining to distribution
0009 # of the software without specific, written prior permission.
0010 # VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
0011 # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
0012 # VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
0013 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
0014 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
0015 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0016 
0017 """
0018 Additional handlers for the logging package for Python. The core package is
0019 based on PEP 282 and comments thereto in comp.lang.python, and influenced by
0020 Apache's log4j system.
0021 
0022 Should work under Python versions >= 1.5.2, except that source line
0023 information is not available unless 'sys._getframe()' is.
0024 
0025 Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
0026 
0027 To use, simply 'import logging' and log away!
0028 """
0029 
0030 import sys, logging, socket, types, os, string, cPickle, struct, time, glob
0031 
0032 #
0033 # Some constants...
0034 #
0035 
0036 DEFAULT_TCP_LOGGING_PORT    = 9020
0037 DEFAULT_UDP_LOGGING_PORT    = 9021
0038 DEFAULT_HTTP_LOGGING_PORT   = 9022
0039 DEFAULT_SOAP_LOGGING_PORT   = 9023
0040 SYSLOG_UDP_PORT             = 514
0041 
0042 class BaseRotatingHandler(logging.FileHandler):
0043     """
0044     Base class for handlers that rotate log files at a certain point.
0045     Not meant to be instantiated directly.  Instead, use RotatingFileHandler
0046     or TimedRotatingFileHandler.
0047     """
0048     def __init__(self, filename, mode):
0049         """
0050         Use the specified filename for streamed logging
0051         """
0052         logging.FileHandler.__init__(self, filename, mode)
0053 
0054     def emit(self, record):
0055         """
0056         Emit a record.
0057 
0058         Output the record to the file, catering for rollover as described
0059         in doRollover().
0060         """
0061         try:
0062             if self.shouldRollover(record):
0063                 self.doRollover()
0064             logging.FileHandler.emit(self, record)
0065         except:
0066             self.handleError(record)
0067 
0068 class RotatingFileHandler(BaseRotatingHandler):
0069     """
0070     Handler for logging to a set of files, which switches from one file
0071     to the next when the current file reaches a certain size.
0072     """
0073     def __init__(self, filename, mode="a", maxBytes=0, backupCount=0):
0074         """
0075         Open the specified file and use it as the stream for logging.
0076 
0077         By default, the file grows indefinitely. You can specify particular
0078         values of maxBytes and backupCount to allow the file to rollover at
0079         a predetermined size.
0080 
0081         Rollover occurs whenever the current log file is nearly maxBytes in
0082         length. If backupCount is >= 1, the system will successively create
0083         new files with the same pathname as the base file, but with extensions
0084         ".1", ".2" etc. appended to it. For example, with a backupCount of 5
0085         and a base file name of "app.log", you would get "app.log",
0086         "app.log.1", "app.log.2", ... through to "app.log.5". The file being
0087         written to is always "app.log" - when it gets filled up, it is closed
0088         and renamed to "app.log.1", and if files "app.log.1", "app.log.2" etc.
0089         exist, then they are renamed to "app.log.2", "app.log.3" etc.
0090         respectively.
0091 
0092         If maxBytes is zero, rollover never occurs.
0093         """
0094         self.mode = mode
0095         if maxBytes > 0:
0096             self.mode = "a" # doesn't make sense otherwise!
0097         BaseRotatingHandler.__init__(self, filename, self.mode)
0098         self.maxBytes = maxBytes
0099         self.backupCount = backupCount
0100 
0101     def doRollover(self):
0102         """
0103         Do a rollover, as described in __init__().
0104         """
0105 
0106         self.stream.close()
0107         if self.backupCount > 0:
0108             for i in range(self.backupCount - 1, 0, -1):
0109                 sfn = "%s.%d" % (self.baseFilename, i)
0110                 dfn = "%s.%d" % (self.baseFilename, i + 1)
0111                 if os.path.exists(sfn):
0112                     #print "%s -> %s" % (sfn, dfn)
0113                     if os.path.exists(dfn):
0114                         os.remove(dfn)
0115                     os.rename(sfn, dfn)
0116             dfn = self.baseFilename + ".1"
0117             if os.path.exists(dfn):
0118                 os.remove(dfn)
0119             os.rename(self.baseFilename, dfn)
0120             #print "%s -> %s" % (self.baseFilename, dfn)
0121         self.stream = open(self.baseFilename, "w")
0122 
0123     def shouldRollover(self, record):
0124         """
0125         Determine if rollover should occur.
0126 
0127         Basically, see if the supplied record would cause the file to exceed
0128         the size limit we have.
0129         """
0130         if self.maxBytes > 0:                   # are we rolling over?
0131             msg = "%s\n" % self.format(record)
0132             self.stream.seek(0, 2)  #due to non-posix-compliant Windows feature
0133             if self.stream.tell() + len(msg) >= self.maxBytes:
0134                 return 1
0135         return 0
0136 
0137 class TimedRotatingFileHandler(BaseRotatingHandler):
0138     """
0139     Handler for logging to a file, rotating the log file at certain timed
0140     intervals.
0141 
0142     If backupCount is > 0, when rollover is done, no more than backupCount
0143     files are kept - the oldest ones are deleted.
0144     """
0145     def __init__(self, filename, when='h', interval=1, backupCount=0):
0146         BaseRotatingHandler.__init__(self, filename, 'a')
0147         self.when = string.upper(when)
0148         self.backupCount = backupCount
0149         # Calculate the real rollover interval, which is just the number of
0150         # seconds between rollovers.  Also set the filename suffix used when
0151         # a rollover occurs.  Current 'when' events supported:
0152         # S - Seconds
0153         # M - Minutes
0154         # H - Hours
0155         # D - Days
0156         # midnight - roll over at midnight
0157         # W{0-6} - roll over on a certain day; 0 - Monday
0158         #
0159         # Case of the 'when' specifier is not important; lower or upper case
0160         # will work.
0161         currentTime = int(time.time())
0162         if self.when == 'S':
0163             self.interval = 1 # one second
0164             self.suffix = "%Y-%m-%d_%H-%M-%S"
0165         elif self.when == 'M':
0166             self.interval = 60 # one minute
0167             self.suffix = "%Y-%m-%d_%H-%M"
0168         elif self.when == 'H':
0169             self.interval = 60 * 60 # one hour
0170             self.suffix = "%Y-%m-%d_%H"
0171         elif self.when == 'D' or self.when == 'MIDNIGHT':
0172             self.interval = 60 * 60 * 24 # one day
0173             self.suffix = "%Y-%m-%d"
0174         elif self.when.startswith('W'):
0175             self.interval = 60 * 60 * 24 * 7 # one week
0176             if len(self.when) != 2:
0177                 raise ValueError("You must specify a day for weekly rollover from 0 to 6 (0 is Monday): %s" % self.when)
0178             if self.when[1] < '0' or self.when[1] > '6':
0179                 raise ValueError("Invalid day specified for weekly rollover: %s" % self.when)
0180             self.dayOfWeek = int(self.when[1])
0181             self.suffix = "%Y-%m-%d"
0182         else:
0183             raise ValueError("Invalid rollover interval specified: %s" % self.when)
0184 
0185         self.interval = self.interval * interval # multiply by units requested
0186         self.rolloverAt = currentTime + self.interval
0187 
0188         # If we are rolling over at midnight or weekly, then the interval is already known.
0189         # What we need to figure out is WHEN the next interval is.  In other words,
0190         # if you are rolling over at midnight, then your base interval is 1 day,
0191         # but you want to start that one day clock at midnight, not now.  So, we
0192         # have to fudge the rolloverAt value in order to trigger the first rollover
0193         # at the right time.  After that, the regular interval will take care of
0194         # the rest.  Note that this code doesn't care about leap seconds. :)
0195         if self.when == 'MIDNIGHT' or self.when.startswith('W'):
0196             # This could be done with less code, but I wanted it to be clear
0197             t = time.localtime(currentTime)
0198             currentHour = t[3]
0199             currentMinute = t[4]
0200             currentSecond = t[5]
0201             # r is the number of seconds left between now and midnight
0202             r = (24 - currentHour) * 60 * 60 # number of hours in seconds
0203             r = r + (59 - currentMinute) * 60 # plus the number of minutes (in secs)
0204             r = r + (59 - currentSecond) # plus the number of seconds
0205             self.rolloverAt = currentTime + r
0206             # If we are rolling over on a certain day, add in the number of days until
0207             # the next rollover, but offset by 1 since we just calculated the time
0208             # until the next day starts.  There are three cases:
0209             # Case 1) The day to rollover is today; in this case, do nothing
0210             # Case 2) The day to rollover is further in the interval (i.e., today is
0211             #         day 2 (Wednesday) and rollover is on day 6 (Sunday).  Days to
0212             #         next rollover is simply 6 - 2 - 1, or 3.
0213             # Case 3) The day to rollover is behind us in the interval (i.e., today
0214             #         is day 5 (Saturday) and rollover is on day 3 (Thursday).
0215             #         Days to rollover is 6 - 5 + 3, or 4.  In this case, it's the
0216             #         number of days left in the current week (1) plus the number
0217             #         of days in the next week until the rollover day (3).
0218             if when.startswith('W'):
0219                 day = t[6] # 0 is Monday
0220                 if day > self.dayOfWeek:
0221                     daysToWait = (day - self.dayOfWeek) - 1
0222                     self.rolloverAt = self.rolloverAt + (daysToWait * (60 * 60 * 24))
0223                 if day < self.dayOfWeek:
0224                     daysToWait = (6 - self.dayOfWeek) + day
0225                     self.rolloverAt = self.rolloverAt + (daysToWait * (60 * 60 * 24))
0226 
0227         #print "Will rollover at %d, %d seconds from now" % (self.rolloverAt, self.rolloverAt - currentTime)
0228 
0229     def shouldRollover(self, record):
0230         """
0231         Determine if rollover should occur
0232 
0233         record is not used, as we are just comparing times, but it is needed so
0234         the method siguratures are the same
0235         """
0236         t = int(time.time())
0237         if t >= self.rolloverAt:
0238             return 1
0239         #print "No need to rollover: %d, %d" % (t, self.rolloverAt)
0240         return 0
0241 
0242     def doRollover(self):
0243         """
0244         do a rollover; in this case, a date/time stamp is appended to the filename
0245         when the rollover happens.  However, you want the file to be named for the
0246         start of the interval, not the current time.  If there is a backup count,
0247         then we have to get a list of matching filenames, sort them and remove
0248         the one with the oldest suffix.
0249         """
0250         self.stream.close()
0251         # get the time that this sequence started at and make it a TimeTuple
0252         t = self.rolloverAt - self.interval
0253         timeTuple = time.localtime(t)
0254         dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple)
0255         if os.path.exists(dfn):
0256             os.remove(dfn)
0257         os.rename(self.baseFilename, dfn)
0258         if self.backupCount > 0:
0259             # find the oldest log file and delete it
0260             s = glob.glob(self.baseFilename + ".20*")
0261             if len(s) > self.backupCount:
0262                 s.sort()
0263                 os.remove(s[0])
0264         #print "%s -> %s" % (self.baseFilename, dfn)
0265         self.stream = open(self.baseFilename, "w")
0266         self.rolloverAt = int(time.time()) + self.interval
0267 
0268 class SocketHandler(logging.Handler):
0269     """
0270     A handler class which writes logging records, in pickle format, to
0271     a streaming socket. The socket is kept open across logging calls.
0272     If the peer resets it, an attempt is made to reconnect on the next call.
0273     The pickle which is sent is that of the LogRecord's attribute dictionary
0274     (__dict__), so that the receiver does not need to have the logging module
0275     installed in order to process the logging event.
0276 
0277     To unpickle the record at the receiving end into a LogRecord, use the
0278     makeLogRecord function.
0279     """
0280 
0281     def __init__(self, host, port):
0282         """
0283         Initializes the handler with a specific host address and port.
0284 
0285         The attribute 'closeOnError' is set to 1 - which means that if
0286         a socket error occurs, the socket is silently closed and then
0287         reopened on the next logging call.
0288         """
0289         logging.Handler.__init__(self)
0290         self.host = host
0291         self.port = port
0292         self.sock = None
0293         self.closeOnError = 0
0294         self.retryTime = None
0295         #
0296         # Exponential backoff parameters.
0297         #
0298         self.retryStart = 1.0
0299         self.retryMax = 30.0
0300         self.retryFactor = 2.0
0301 
0302     def makeSocket(self):
0303         """
0304         A factory method which allows subclasses to define the precise
0305         type of socket they want.
0306         """
0307         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
0308         s.connect((self.host, self.port))
0309         return s
0310 
0311     def createSocket(self):
0312         """
0313         Try to create a socket, using an exponential backoff with
0314         a max retry time. Thanks to Robert Olson for the original patch
0315         (SF #815911) which has been slightly refactored.
0316         """
0317         now = time.time()
0318         # Either retryTime is None, in which case this
0319         # is the first time back after a disconnect, or
0320         # we've waited long enough.
0321         if self.retryTime is None:
0322             attempt = 1
0323         else:
0324             attempt = (now >= self.retryTime)
0325         if attempt:
0326             try:
0327                 self.sock = self.makeSocket()
0328                 self.retryTime = None # next time, no delay before trying
0329             except:
0330                 #Creation failed, so set the retry time and return.
0331                 if self.retryTime is None:
0332                     self.retryPeriod = self.retryStart
0333                 else:
0334                     self.retryPeriod = self.retryPeriod * self.retryFactor
0335                     if self.retryPeriod > self.retryMax:
0336                         self.retryPeriod = self.retryMax
0337                 self.retryTime = now + self.retryPeriod
0338 
0339     def send(self, s):
0340         """
0341         Send a pickled string to the socket.
0342 
0343         This function allows for partial sends which can happen when the
0344         network is busy.
0345         """
0346         if self.sock is None:
0347             self.createSocket()
0348         #self.sock can be None either because we haven't reached the retry
0349         #time yet, or because we have reached the retry time and retried,
0350         #but are still unable to connect.
0351         if self.sock:
0352             try:
0353                 if hasattr(self.sock, "sendall"):
0354                     self.sock.sendall(s)
0355                 else:
0356                     sentsofar = 0
0357                     left = len(s)
0358                     while left > 0:
0359                         sent = self.sock.send(s[sentsofar:])
0360                         sentsofar = sentsofar + sent
0361                         left = left - sent
0362             except socket.error:
0363                 self.sock.close()
0364                 self.sock = None  # so we can call createSocket next time
0365 
0366     def makePickle(self, record):
0367         """
0368         Pickles the record in binary format with a length prefix, and
0369         returns it ready for transmission across the socket.
0370         """
0371         ei = record.exc_info
0372         if ei:
0373             dummy = self.format(record) # just to get traceback text into record.exc_text
0374             record.exc_info = None  # to avoid Unpickleable error
0375         s = cPickle.dumps(record.__dict__, 1)
0376         if ei:
0377             record.exc_info = ei  # for next handler
0378         slen = struct.pack(">L", len(s))
0379         return slen + s
0380 
0381     def handleError(self, record):
0382         """
0383         Handle an error during logging.
0384 
0385         An error has occurred during logging. Most likely cause -
0386         connection lost. Close the socket so that we can retry on the
0387         next event.
0388         """
0389         if self.closeOnError and self.sock:
0390             self.sock.close()
0391             self.sock = None        #try to reconnect next time
0392         else:
0393             logging.Handler.handleError(self, record)
0394 
0395     def emit(self, record):
0396         """
0397         Emit a record.
0398 
0399         Pickles the record and writes it to the socket in binary format.
0400         If there is an error with the socket, silently drop the packet.
0401         If there was a problem with the socket, re-establishes the
0402         socket.
0403         """
0404         try:
0405             s = self.makePickle(record)
0406             self.send(s)
0407         except:
0408             self.handleError(record)
0409 
0410     def close(self):
0411         """
0412         Closes the socket.
0413         """
0414         if self.sock:
0415             self.sock.close()
0416             self.sock = None
0417         logging.Handler.close(self)
0418 
0419 class DatagramHandler(SocketHandler):
0420     """
0421     A handler class which writes logging records, in pickle format, to
0422     a datagram socket.  The pickle which is sent is that of the LogRecord's
0423     attribute dictionary (__dict__), so that the receiver does not need to
0424     have the logging module installed in order to process the logging event.
0425 
0426     To unpickle the record at the receiving end into a LogRecord, use the
0427     makeLogRecord function.
0428 
0429     """
0430     def __init__(self, host, port):
0431         """
0432         Initializes the handler with a specific host address and port.
0433         """
0434         SocketHandler.__init__(self, host, port)
0435         self.closeOnError = 0
0436 
0437     def makeSocket(self):
0438         """
0439         The factory method of SocketHandler is here overridden to create
0440         a UDP socket (SOCK_DGRAM).
0441         """
0442         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
0443         return s
0444 
0445     def send(self, s):
0446         """
0447         Send a pickled string to a socket.
0448 
0449         This function no longer allows for partial sends which can happen
0450         when the network is busy - UDP does not guarantee delivery and
0451         can deliver packets out of sequence.
0452         """
0453         if self.sock is None:
0454             self.createSocket()
0455         self.sock.sendto(s, (self.host, self.port))
0456 
0457 class SysLogHandler(logging.Handler):
0458     """
0459     A handler class which sends formatted logging records to a syslog
0460     server. Based on Sam Rushing's syslog module:
0461     http://www.nightmare.com/squirl/python-ext/misc/syslog.py
0462     Contributed by Nicolas Untz (after which minor refactoring changes
0463     have been made).
0464     """
0465 
0466     # from <linux/sys/syslog.h>:
0467     # ======================================================================
0468     # priorities/facilities are encoded into a single 32-bit quantity, where
0469     # the bottom 3 bits are the priority (0-7) and the top 28 bits are the
0470     # facility (0-big number). Both the priorities and the facilities map
0471     # roughly one-to-one to strings in the syslogd(8) source code.  This
0472     # mapping is included in this file.
0473     #
0474     # priorities (these are ordered)
0475 
0476     LOG_EMERG     = 0       #  system is unusable
0477     LOG_ALERT     = 1       #  action must be taken immediately
0478     LOG_CRIT      = 2       #  critical conditions
0479     LOG_ERR       = 3       #  error conditions
0480     LOG_WARNING   = 4       #  warning conditions
0481     LOG_NOTICE    = 5       #  normal but significant condition
0482     LOG_INFO      = 6       #  informational
0483     LOG_DEBUG     = 7       #  debug-level messages
0484 
0485     #  facility codes
0486     LOG_KERN      = 0       #  kernel messages
0487     LOG_USER      = 1       #  random user-level messages
0488     LOG_MAIL      = 2       #  mail system
0489     LOG_DAEMON    = 3       #  system daemons
0490     LOG_AUTH      = 4       #  security/authorization messages
0491     LOG_SYSLOG    = 5       #  messages generated internally by syslogd
0492     LOG_LPR       = 6       #  line printer subsystem
0493     LOG_NEWS      = 7       #  network news subsystem
0494     LOG_UUCP      = 8       #  UUCP subsystem
0495     LOG_CRON      = 9       #  clock daemon
0496     LOG_AUTHPRIV  = 10  #  security/authorization messages (private)
0497 
0498     #  other codes through 15 reserved for system use
0499     LOG_LOCAL0    = 16      #  reserved for local use
0500     LOG_LOCAL1    = 17      #  reserved for local use
0501     LOG_LOCAL2    = 18      #  reserved for local use
0502     LOG_LOCAL3    = 19      #  reserved for local use
0503     LOG_LOCAL4    = 20      #  reserved for local use
0504     LOG_LOCAL5    = 21      #  reserved for local use
0505     LOG_LOCAL6    = 22      #  reserved for local use
0506     LOG_LOCAL7    = 23      #  reserved for local use
0507 
0508     priority_names = {
0509         "alert":    LOG_ALERT,
0510         "crit":     LOG_CRIT,
0511         "critical": LOG_CRIT,
0512         "debug":    LOG_DEBUG,
0513         "emerg":    LOG_EMERG,
0514         "err":      LOG_ERR,
0515         "error":    LOG_ERR,        #  DEPRECATED
0516         "info":     LOG_INFO,
0517         "notice":   LOG_NOTICE,
0518         "panic":    LOG_EMERG,      #  DEPRECATED
0519         "warn":     LOG_WARNING,    #  DEPRECATED
0520         "warning":  LOG_WARNING,
0521         }
0522 
0523     facility_names = {
0524         "auth":     LOG_AUTH,
0525         "authpriv": LOG_AUTHPRIV,
0526         "cron":     LOG_CRON,
0527         "daemon":   LOG_DAEMON,
0528         "kern":     LOG_KERN,
0529         "lpr":      LOG_LPR,
0530         "mail":     LOG_MAIL,
0531         "news":     LOG_NEWS,
0532         "security": LOG_AUTH,       #  DEPRECATED
0533         "syslog":   LOG_SYSLOG,
0534         "user":     LOG_USER,
0535         "uucp":     LOG_UUCP,
0536         "local0":   LOG_LOCAL0,
0537         "local1":   LOG_LOCAL1,
0538         "local2":   LOG_LOCAL2,
0539         "local3":   LOG_LOCAL3,
0540         "local4":   LOG_LOCAL4,
0541         "local5":   LOG_LOCAL5,
0542         "local6":   LOG_LOCAL6,
0543         "local7":   LOG_LOCAL7,
0544         }
0545 
0546     def __init__(self, address=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER):
0547         """
0548         Initialize a handler.
0549 
0550         If address is specified as a string, UNIX socket is used.
0551         If facility is not specified, LOG_USER is used.
0552         """
0553         logging.Handler.__init__(self)
0554 
0555         self.address = address
0556         self.facility = facility
0557         if type(address) == types.StringType:
0558             self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
0559             # syslog may require either DGRAM or STREAM sockets
0560             try:
0561                 self.socket.connect(address)
0562             except socket.error:
0563                 self.socket.close()
0564                 self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
0565             self.socket.connect(address)
0566             self.unixsocket = 1
0567         else:
0568             self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
0569             self.unixsocket = 0
0570 
0571         self.formatter = None
0572 
0573     # curious: when talking to the unix-domain '/dev/log' socket, a
0574     #   zero-terminator seems to be required.  this string is placed
0575     #   into a class variable so that it can be overridden if
0576     #   necessary.
0577     log_format_string = '<%d>%s\000'
0578 
0579     def encodePriority (self, facility, priority):
0580         """
0581         Encode the facility and priority. You can pass in strings or
0582         integers - if strings are passed, the facility_names and
0583         priority_names mapping dictionaries are used to convert them to
0584         integers.
0585         """
0586         if type(facility) == types.StringType:
0587             facility = self.facility_names[facility]
0588         if type(priority) == types.StringType:
0589             priority = self.priority_names[priority]
0590         return (facility << 3) | priority
0591 
0592     def close (self):
0593         """
0594         Closes the socket.
0595         """
0596         if self.unixsocket:
0597             self.socket.close()
0598         logging.Handler.close(self)
0599 
0600     def emit(self, record):
0601         """
0602         Emit a record.
0603 
0604         The record is formatted, and then sent to the syslog server. If
0605         exception information is present, it is NOT sent to the server.
0606         """
0607         msg = self.format(record)
0608         """
0609         We need to convert record level to lowercase, maybe this will
0610         change in the future.
0611         """
0612         msg = self.log_format_string % (
0613             self.encodePriority(self.facility,
0614                                 string.lower(record.levelname)),
0615             msg)
0616         try:
0617             if self.unixsocket:
0618                 self.socket.send(msg)
0619             else:
0620                 self.socket.sendto(msg, self.address)
0621         except:
0622             self.handleError(record)
0623 
0624 class SMTPHandler(logging.Handler):
0625     """
0626     A handler class which sends an SMTP email for each logging event.
0627     """
0628     def __init__(self, mailhost, fromaddr, toaddrs, subject):
0629         """
0630         Initialize the handler.
0631 
0632         Initialize the instance with the from and to addresses and subject
0633         line of the email. To specify a non-standard SMTP port, use the
0634         (host, port) tuple format for the mailhost argument.
0635         """
0636         logging.Handler.__init__(self)
0637         if type(mailhost) == types.TupleType:
0638             host, port = mailhost
0639             self.mailhost = host
0640             self.mailport = port
0641         else:
0642             self.mailhost = mailhost
0643             self.mailport = None
0644         self.fromaddr = fromaddr
0645         if type(toaddrs) == types.StringType:
0646             toaddrs = [toaddrs]
0647         self.toaddrs = toaddrs
0648         self.subject = subject
0649 
0650     def getSubject(self, record):
0651         """
0652         Determine the subject for the email.
0653 
0654         If you want to specify a subject line which is record-dependent,
0655         override this method.
0656         """
0657         return self.subject
0658 
0659     weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
0660 
0661     monthname = [None,
0662                  'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
0663                  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
0664 
0665     def date_time(self):
0666         """
0667         Return the current date and time formatted for a MIME header.
0668         Needed for Python 1.5.2 (no email package available)
0669         """
0670         year, month, day, hh, mm, ss, wd, y, z = time.gmtime(time.time())
0671         s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
0672                 self.weekdayname[wd],
0673                 day, self.monthname[month], year,
0674                 hh, mm, ss)
0675         return s
0676 
0677     def emit(self, record):
0678         """
0679         Emit a record.
0680 
0681         Format the record and send it to the specified addressees.
0682         """
0683         try:
0684             import smtplib
0685             try:
0686                 from email.Utils import formatdate
0687             except:
0688                 formatdate = self.date_time
0689             port = self.mailport
0690             if not port:
0691                 port = smtplib.SMTP_PORT
0692             smtp = smtplib.SMTP(self.mailhost, port)
0693             msg = self.format(record)
0694             msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
0695                             self.fromaddr,
0696                             string.join(self.toaddrs, ","),
0697                             self.getSubject(record),
0698                             formatdate(), msg)
0699             smtp.sendmail(self.fromaddr, self.toaddrs, msg)
0700             smtp.quit()
0701         except:
0702             self.handleError(record)
0703 
0704 class NTEventLogHandler(logging.Handler):
0705     """
0706     A handler class which sends events to the NT Event Log. Adds a
0707     registry entry for the specified application name. If no dllname is
0708     provided, win32service.pyd (which contains some basic message
0709     placeholders) is used. Note that use of these placeholders will make
0710     your event logs big, as the entire message source is held in the log.
0711     If you want slimmer logs, you have to pass in the name of your own DLL
0712     which contains the message definitions you want to use in the event log.
0713     """
0714     def __init__(self, appname, dllname=None, logtype="Application"):
0715         logging.Handler.__init__(self)
0716         try:
0717             import win32evtlogutil, win32evtlog
0718             self.appname = appname
0719             self._welu = win32evtlogutil
0720             if not dllname:
0721                 dllname = os.path.split(self._welu.__file__)
0722                 dllname = os.path.split(dllname[0])
0723                 dllname = os.path.join(dllname[0], r'win32service.pyd')
0724             self.dllname = dllname
0725             self.logtype = logtype
0726             self._welu.AddSourceToRegistry(appname, dllname, logtype)
0727             self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE
0728             self.typemap = {
0729                 logging.DEBUG   : win32evtlog.EVENTLOG_INFORMATION_TYPE,
0730                 logging.INFO    : win32evtlog.EVENTLOG_INFORMATION_TYPE,
0731                 logging.WARNING : win32evtlog.EVENTLOG_WARNING_TYPE,
0732                 logging.ERROR   : win32evtlog.EVENTLOG_ERROR_TYPE,
0733                 logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
0734          }
0735         except ImportError:
0736             print "The Python Win32 extensions for NT (service, event "\
0737                         "logging) appear not to be available."
0738             self._welu = None
0739 
0740     def getMessageID(self, record):
0741         """
0742         Return the message ID for the event record. If you are using your
0743         own messages, you could do this by having the msg passed to the
0744         logger being an ID rather than a formatting string. Then, in here,
0745         you could use a dictionary lookup to get the message ID. This
0746         version returns 1, which is the base message ID in win32service.pyd.
0747         """
0748         return 1
0749 
0750     def getEventCategory(self, record):
0751         """
0752         Return the event category for the record.
0753 
0754         Override this if you want to specify your own categories. This version
0755         returns 0.
0756         """
0757         return 0
0758 
0759     def getEventType(self, record):
0760         """
0761         Return the event type for the record.
0762 
0763         Override this if you want to specify your own types. This version does
0764         a mapping using the handler's typemap attribute, which is set up in
0765         __init__() to a dictionary which contains mappings for DEBUG, INFO,
0766         WARNING, ERROR and CRITICAL. If you are using your own levels you will
0767         either need to override this method or place a suitable dictionary in
0768         the handler's typemap attribute.
0769         """
0770         return self.typemap.get(record.levelno, self.deftype)
0771 
0772     def emit(self, record):
0773         """
0774         Emit a record.
0775 
0776         Determine the message ID, event category and event type. Then
0777         log the message in the NT event log.
0778         """
0779         if self._welu:
0780             try:
0781                 id = self.getMessageID(record)
0782                 cat = self.getEventCategory(record)
0783                 type = self.getEventType(record)
0784                 msg = self.format(record)
0785                 self._welu.ReportEvent(self.appname, id, cat, type, [msg])
0786             except:
0787                 self.handleError(record)
0788 
0789     def close(self):
0790         """
0791         Clean up this handler.
0792 
0793         You can remove the application name from the registry as a
0794         source of event log entries. However, if you do this, you will
0795         not be able to see the events as you intended in the Event Log
0796         Viewer - it needs to be able to access the registry to get the
0797         DLL name.
0798         """
0799         #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype)
0800         logging.Handler.close(self)
0801 
0802 class HTTPHandler(logging.Handler):
0803     """
0804     A class which sends records to a Web server, using either GET or
0805     POST semantics.
0806     """
0807     def __init__(self, host, url, method="GET"):
0808         """
0809         Initialize the instance with the host, the request URL, and the method
0810         ("GET" or "POST")
0811         """
0812         logging.Handler.__init__(self)
0813         method = string.upper(method)
0814         if method not in ["GET", "POST"]:
0815             raise ValueError, "method must be GET or POST"
0816         self.host = host
0817         self.url = url
0818         self.method = method
0819 
0820     def mapLogRecord(self, record):
0821         """
0822         Default implementation of mapping the log record into a dict
0823         that is sent as the CGI data. Overwrite in your class.
0824         Contributed by Franz  Glasner.
0825         """
0826         return record.__dict__
0827 
0828     def emit(self, record):
0829         """
0830         Emit a record.
0831 
0832         Send the record to the Web server as an URL-encoded dictionary
0833         """
0834         try:
0835             import httplib, urllib
0836             h = httplib.HTTP(self.host)
0837             url = self.url
0838             data = urllib.urlencode(self.mapLogRecord(record))
0839             if self.method == "GET":
0840                 if (string.find(url, '?') >= 0):
0841                     sep = '&'
0842                 else:
0843                     sep = '?'
0844                 url = url + "%c%s" % (sep, data)
0845             h.putrequest(self.method, url)
0846             if self.method == "POST":
0847                 h.putheader("Content-length", str(len(data)))
0848             h.endheaders()
0849             if self.method == "POST":
0850                 h.send(data)
0851             h.getreply()    #can't do anything with the result
0852         except:
0853             self.handleError(record)
0854 
0855 class BufferingHandler(logging.Handler):
0856     """
0857   A handler class which buffers logging records in memory. Whenever each
0858   record is added to the buffer, a check is made to see if the buffer should
0859   be flushed. If it should, then flush() is expected to do what's needed.
0860     """
0861     def __init__(self, capacity):
0862         """
0863         Initialize the handler with the buffer size.
0864         """
0865         logging.Handler.__init__(self)
0866         self.capacity = capacity
0867         self.buffer = []
0868 
0869     def shouldFlush(self, record):
0870         """
0871         Should the handler flush its buffer?
0872 
0873         Returns true if the buffer is up to capacity. This method can be
0874         overridden to implement custom flushing strategies.
0875         """
0876         return (len(self.buffer) >= self.capacity)
0877 
0878     def emit(self, record):
0879         """
0880         Emit a record.
0881 
0882         Append the record. If shouldFlush() tells us to, call flush() to process
0883         the buffer.
0884         """
0885         self.buffer.append(record)
0886         if self.shouldFlush(record):
0887             self.flush()
0888 
0889     def flush(self):
0890         """
0891         Override to implement custom flushing behaviour.
0892 
0893         This version just zaps the buffer to empty.
0894         """
0895         self.buffer = []
0896 
0897     def close(self):
0898         """
0899         Close the handler.
0900 
0901         This version just flushes and chains to the parent class' close().
0902         """
0903         self.flush()
0904         logging.Handler.close(self)
0905 
0906 class MemoryHandler(BufferingHandler):
0907     """
0908     A handler class which buffers logging records in memory, periodically
0909     flushing them to a target handler. Flushing occurs whenever the buffer
0910     is full, or when an event of a certain severity or greater is seen.
0911     """
0912     def __init__(self, capacity, flushLevel=logging.ERROR, target=None):
0913         """
0914         Initialize the handler with the buffer size, the level at which
0915         flushing should occur and an optional target.
0916 
0917         Note that without a target being set either here or via setTarget(),
0918         a MemoryHandler is no use to anyone!
0919         """
0920         BufferingHandler.__init__(self, capacity)
0921         self.flushLevel = flushLevel
0922         self.target = target
0923 
0924     def shouldFlush(self, record):
0925         """
0926         Check for buffer full or a record at the flushLevel or higher.
0927         """
0928         return (len(self.buffer) >= self.capacity) or \
0929                 (record.levelno >= self.flushLevel)
0930 
0931     def setTarget(self, target):
0932         """
0933         Set the target handler for this handler.
0934         """
0935         self.target = target
0936 
0937     def flush(self):
0938         """
0939         For a MemoryHandler, flushing means just sending the buffered
0940         records to the target, if there is one. Override if you want
0941         different behaviour.
0942         """
0943         if self.target:
0944             for record in self.buffer:
0945                 self.target.handle(record)
0946             self.buffer = []
0947 
0948     def close(self):
0949         """
0950         Flush, set the target to None and lose the buffer.
0951         """
0952         self.flush()
0953         self.target = None
0954         BufferingHandler.close(self)
0955 

Generated by PyXR 0.9.4
SourceForge.net Logo