home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / handlers.py < prev    next >
Text File  |  2003-12-30  |  26KB  |  729 lines

  1. # Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
  2. #
  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.
  16.  
  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.
  20.  
  21. Should work under Python versions >= 1.5.2, except that source line
  22. information is not available unless 'inspect' is.
  23.  
  24. Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
  25.  
  26. To use, simply 'import logging' and log away!
  27. """
  28.  
  29. import sys, logging, socket, types, os, string, cPickle, struct, time
  30.  
  31. from SocketServer import ThreadingTCPServer, StreamRequestHandler
  32.  
  33. #
  34. # Some constants...
  35. #
  36.  
  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
  42.  
  43.  
  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.
  48.  
  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.
  52.  
  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.
  63.  
  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"
  71.  
  72.     def doRollover(self):
  73.         """
  74.         Do a rollover, as described in __init__().
  75.         """
  76.  
  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")
  93.  
  94.     def emit(self, record):
  95.         """
  96.         Emit a record.
  97.  
  98.         Output the record to the file, catering for rollover as described
  99.         in doRollover().
  100.         """
  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)
  107.  
  108.  
  109. class SocketHandler(logging.Handler):
  110.     """
  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.
  117.  
  118.     To unpickle the record at the receiving end into a LogRecord, use the
  119.     makeLogRecord function.
  120.     """
  121.  
  122.     def __init__(self, host, port):
  123.         """
  124.         Initializes the handler with a specific host address and port.
  125.  
  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.
  129.         """
  130.         logging.Handler.__init__(self)
  131.         self.host = host
  132.         self.port = port
  133.         self.sock = None
  134.         self.closeOnError = 0
  135.  
  136.     def makeSocket(self):
  137.         """
  138.         A factory method which allows subclasses to define the precise
  139.         type of socket they want.
  140.         """
  141.         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  142.         s.connect((self.host, self.port))
  143.         return s
  144.  
  145.     def send(self, s):
  146.         """
  147.         Send a pickled string to the socket.
  148.  
  149.         This function allows for partial sends which can happen when the
  150.         network is busy.
  151.         """
  152.         if hasattr(self.sock, "sendall"):
  153.             self.sock.sendall(s)
  154.         else:
  155.             sentsofar = 0
  156.             left = len(s)
  157.             while left > 0:
  158.                 sent = self.sock.send(s[sentsofar:])
  159.                 sentsofar = sentsofar + sent
  160.                 left = left - sent
  161.  
  162.     def makePickle(self, record):
  163.         """
  164.         Pickles the record in binary format with a length prefix, and
  165.         returns it ready for transmission across the socket.
  166.         """
  167.         s = cPickle.dumps(record.__dict__, 1)
  168.         #n = len(s)
  169.         #slen = "%c%c" % ((n >> 8) & 0xFF, n & 0xFF)
  170.         slen = struct.pack(">L", len(s))
  171.         return slen + s
  172.  
  173.     def handleError(self, record):
  174.         """
  175.         Handle an error during logging.
  176.  
  177.         An error has occurred during logging. Most likely cause -
  178.         connection lost. Close the socket so that we can retry on the
  179.         next event.
  180.         """
  181.         if self.closeOnError and self.sock:
  182.             self.sock.close()
  183.             self.sock = None        #try to reconnect next time
  184.         else:
  185.             logging.Handler.handleError(self, record)
  186.  
  187.     def emit(self, record):
  188.         """
  189.         Emit a record.
  190.  
  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
  194.         socket.
  195.         """
  196.         try:
  197.             s = self.makePickle(record)
  198.             if not self.sock:
  199.                 self.sock = self.makeSocket()
  200.             self.send(s)
  201.         except:
  202.             self.handleError(record)
  203.  
  204.     def close(self):
  205.         """
  206.         Closes the socket.
  207.         """
  208.         if self.sock:
  209.             self.sock.close()
  210.             self.sock = None
  211.  
  212. class DatagramHandler(SocketHandler):
  213.     """
  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.
  218.  
  219.     To unpickle the record at the receiving end into a LogRecord, use the
  220.     makeLogRecord function.
  221.  
  222.     """
  223.     def __init__(self, host, port):
  224.         """
  225.         Initializes the handler with a specific host address and port.
  226.         """
  227.         SocketHandler.__init__(self, host, port)
  228.         self.closeOnError = 0
  229.  
  230.     def makeSocket(self):
  231.         """
  232.         The factory method of SocketHandler is here overridden to create
  233.         a UDP socket (SOCK_DGRAM).
  234.         """
  235.         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  236.         return s
  237.  
  238.     def send(self, s):
  239.         """
  240.         Send a pickled string to a socket.
  241.  
  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.
  245.         """
  246.         self.sock.sendto(s, (self.host, self.port))
  247.  
  248. class SysLogHandler(logging.Handler):
  249.     """
  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
  254.     have been made).
  255.     """
  256.  
  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.
  264.     #
  265.     # priorities (these are ordered)
  266.  
  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
  275.  
  276.     #  facility codes
  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)
  288.  
  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
  298.  
  299.     priority_names = {
  300.         "alert":    LOG_ALERT,
  301.         "crit":     LOG_CRIT,
  302.         "critical": LOG_CRIT,
  303.         "debug":    LOG_DEBUG,
  304.         "emerg":    LOG_EMERG,
  305.         "err":      LOG_ERR,
  306.         "error":    LOG_ERR,        #  DEPRECATED
  307.         "info":     LOG_INFO,
  308.         "notice":   LOG_NOTICE,
  309.         "panic":    LOG_EMERG,      #  DEPRECATED
  310.         "warn":     LOG_WARNING,    #  DEPRECATED
  311.         "warning":  LOG_WARNING,
  312.         }
  313.  
  314.     facility_names = {
  315.         "auth":     LOG_AUTH,
  316.         "authpriv": LOG_AUTHPRIV,
  317.         "cron":     LOG_CRON,
  318.         "daemon":   LOG_DAEMON,
  319.         "kern":     LOG_KERN,
  320.         "lpr":      LOG_LPR,
  321.         "mail":     LOG_MAIL,
  322.         "news":     LOG_NEWS,
  323.         "security": LOG_AUTH,       #  DEPRECATED
  324.         "syslog":   LOG_SYSLOG,
  325.         "user":     LOG_USER,
  326.         "uucp":     LOG_UUCP,
  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,
  335.         }
  336.  
  337.     def __init__(self, address=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER):
  338.         """
  339.         Initialize a handler.
  340.  
  341.         If address is specified as a string, UNIX socket is used.
  342.         If facility is not specified, LOG_USER is used.
  343.         """
  344.         logging.Handler.__init__(self)
  345.  
  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
  351.             try:
  352.                 self.socket.connect(address)
  353.             except socket.error:
  354.                 self.socket.close()
  355.                 self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  356.             self.socket.connect(address)
  357.             self.unixsocket = 1
  358.         else:
  359.             self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  360.             self.unixsocket = 0
  361.  
  362.         self.formatter = None
  363.  
  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
  367.     #   necessary.
  368.     log_format_string = '<%d>%s\000'
  369.  
  370.     def encodePriority (self, facility, priority):
  371.         """
  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
  375.         integers.
  376.         """
  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
  382.  
  383.     def close (self):
  384.         """
  385.         Closes the socket.
  386.         """
  387.         if self.unixsocket:
  388.             self.socket.close()
  389.  
  390.     def emit(self, record):
  391.         """
  392.         Emit a record.
  393.  
  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.
  396.         """
  397.         msg = self.format(record)
  398.         """
  399.         We need to convert record level to lowercase, maybe this will
  400.         change in the future.
  401.         """
  402.         msg = self.log_format_string % (
  403.             self.encodePriority(self.facility,
  404.                                 string.lower(record.levelname)),
  405.             msg)
  406.         try:
  407.             if self.unixsocket:
  408.                 self.socket.send(msg)
  409.             else:
  410.                 self.socket.sendto(msg, self.address)
  411.         except:
  412.             self.handleError(record)
  413.  
  414. class SMTPHandler(logging.Handler):
  415.     """
  416.     A handler class which sends an SMTP email for each logging event.
  417.     """
  418.     def __init__(self, mailhost, fromaddr, toaddrs, subject):
  419.         """
  420.         Initialize the handler.
  421.  
  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.
  425.         """
  426.         logging.Handler.__init__(self)
  427.         if type(mailhost) == types.TupleType:
  428.             host, port = mailhost
  429.             self.mailhost = host
  430.             self.mailport = port
  431.         else:
  432.             self.mailhost = mailhost
  433.             self.mailport = None
  434.         self.fromaddr = fromaddr
  435.         if type(toaddrs) == types.StringType:
  436.             toaddrs = [toaddrs]
  437.         self.toaddrs = toaddrs
  438.         self.subject = subject
  439.  
  440.     def getSubject(self, record):
  441.         """
  442.         Determine the subject for the email.
  443.  
  444.         If you want to specify a subject line which is record-dependent,
  445.         override this method.
  446.         """
  447.         return self.subject
  448.  
  449.     weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  450.  
  451.     monthname = [None,
  452.                  'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  453.                  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
  454.  
  455.     def date_time(self):
  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,
  461.                 hh, mm, ss)
  462.         return s
  463.  
  464.     def emit(self, record):
  465.         """
  466.         Emit a record.
  467.  
  468.         Format the record and send it to the specified addressees.
  469.         """
  470.         try:
  471.             import smtplib
  472.             port = self.mailport
  473.             if not port:
  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" % (
  478.                             self.fromaddr,
  479.                             string.join(self.toaddrs, ","),
  480.                             self.getSubject(record),
  481.                             self.date_time(), msg)
  482.             smtp.sendmail(self.fromaddr, self.toaddrs, msg)
  483.             smtp.quit()
  484.         except:
  485.             self.handleError(record)
  486.  
  487. class NTEventLogHandler(logging.Handler):
  488.     """
  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.
  496.     """
  497.     def __init__(self, appname, dllname=None, logtype="Application"):
  498.         logging.Handler.__init__(self)
  499.         try:
  500.             import win32evtlogutil, win32evtlog
  501.             self.appname = appname
  502.             self._welu = win32evtlogutil
  503.             if not dllname:
  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
  511.             self.typemap = {
  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,
  517.          }
  518.         except ImportError:
  519.             print "The Python Win32 extensions for NT (service, event "\
  520.                         "logging) appear not to be available."
  521.             self._welu = None
  522.  
  523.     def getMessageID(self, record):
  524.         """
  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.
  530.         """
  531.         return 1
  532.  
  533.     def getEventCategory(self, record):
  534.         """
  535.         Return the event category for the record.
  536.  
  537.         Override this if you want to specify your own categories. This version
  538.         returns 0.
  539.         """
  540.         return 0
  541.  
  542.     def getEventType(self, record):
  543.         """
  544.         Return the event type for the record.
  545.  
  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.
  552.         """
  553.         return self.typemap.get(record.levelno, self.deftype)
  554.  
  555.     def emit(self, record):
  556.         """
  557.         Emit a record.
  558.  
  559.         Determine the message ID, event category and event type. Then
  560.         log the message in the NT event log.
  561.         """
  562.         if self._welu:
  563.             try:
  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])
  569.             except:
  570.                 self.handleError(record)
  571.  
  572.     def close(self):
  573.         """
  574.         Clean up this handler.
  575.  
  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
  580.         DLL name.
  581.         """
  582.         #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype)
  583.         pass
  584.  
  585. class HTTPHandler(logging.Handler):
  586.     """
  587.     A class which sends records to a Web server, using either GET or
  588.     POST semantics.
  589.     """
  590.     def __init__(self, host, url, method="GET"):
  591.         """
  592.         Initialize the instance with the host, the request URL, and the method
  593.         ("GET" or "POST")
  594.         """
  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"
  599.         self.host = host
  600.         self.url = url
  601.         self.method = method
  602.  
  603.     def mapLogRecord(self, record):
  604.         """
  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.
  608.         """
  609.         return record.__dict__
  610.  
  611.     def emit(self, record):
  612.         """
  613.         Emit a record.
  614.  
  615.         Send the record to the Web server as an URL-encoded dictionary
  616.         """
  617.         try:
  618.             import httplib, urllib
  619.             h = httplib.HTTP(self.host)
  620.             url = self.url
  621.             data = urllib.urlencode(self.mapLogRecord(record))
  622.             if self.method == "GET":
  623.                 if (string.find(url, '?') >= 0):
  624.                     sep = '&'
  625.                 else:
  626.                     sep = '?'
  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)))
  631.             h.endheaders()
  632.             if self.method == "POST":
  633.                 h.send(data)
  634.             h.getreply()    #can't do anything with the result
  635.         except:
  636.             self.handleError(record)
  637.  
  638. class BufferingHandler(logging.Handler):
  639.     """
  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.
  643.     """
  644.     def __init__(self, capacity):
  645.         """
  646.         Initialize the handler with the buffer size.
  647.         """
  648.         logging.Handler.__init__(self)
  649.         self.capacity = capacity
  650.         self.buffer = []
  651.  
  652.     def shouldFlush(self, record):
  653.         """
  654.         Should the handler flush its buffer?
  655.  
  656.         Returns true if the buffer is up to capacity. This method can be
  657.         overridden to implement custom flushing strategies.
  658.         """
  659.         return (len(self.buffer) >= self.capacity)
  660.  
  661.     def emit(self, record):
  662.         """
  663.         Emit a record.
  664.  
  665.         Append the record. If shouldFlush() tells us to, call flush() to process
  666.         the buffer.
  667.         """
  668.         self.buffer.append(record)
  669.         if self.shouldFlush(record):
  670.             self.flush()
  671.  
  672.     def flush(self):
  673.         """
  674.         Override to implement custom flushing behaviour.
  675.  
  676.         This version just zaps the buffer to empty.
  677.         """
  678.         self.buffer = []
  679.  
  680. class MemoryHandler(BufferingHandler):
  681.     """
  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.
  685.     """
  686.     def __init__(self, capacity, flushLevel=logging.ERROR, target=None):
  687.         """
  688.         Initialize the handler with the buffer size, the level at which
  689.         flushing should occur and an optional target.
  690.  
  691.         Note that without a target being set either here or via setTarget(),
  692.         a MemoryHandler is no use to anyone!
  693.         """
  694.         BufferingHandler.__init__(self, capacity)
  695.         self.flushLevel = flushLevel
  696.         self.target = target
  697.  
  698.     def shouldFlush(self, record):
  699.         """
  700.         Check for buffer full or a record at the flushLevel or higher.
  701.         """
  702.         return (len(self.buffer) >= self.capacity) or \
  703.                 (record.levelno >= self.flushLevel)
  704.  
  705.     def setTarget(self, target):
  706.         """
  707.         Set the target handler for this handler.
  708.         """
  709.         self.target = target
  710.  
  711.     def flush(self):
  712.         """
  713.         For a MemoryHandler, flushing means just sending the buffered
  714.         records to the target, if there is one. Override if you want
  715.         different behaviour.
  716.         """
  717.         if self.target:
  718.             for record in self.buffer:
  719.                 self.target.handle(record)
  720.             self.buffer = []
  721.  
  722.     def close(self):
  723.         """
  724.         Flush, set the target to None and lose the buffer.
  725.         """
  726.         self.flush()
  727.         self.target = None
  728.         self.buffer = []
  729.