ia64/xen-unstable

changeset 1863:b5427b1bb6c1

bitkeeper revision 1.1108.1.8 (40ffc44fV2fs0W-8bRw5B0XcBdmAsw)

Add python 2.3 logging to the tree. Only install
if not present. Convert xend to use logging.
author mjw@wray-m-3.hpl.hp.com
date Thu Jul 22 13:42:39 2004 +0000 (2004-07-22)
parents ba57d25bfe88
children dcfb8f179d72
files .rootkeys tools/python/logging/logging-0.4.9.2/PKG-INFO tools/python/logging/logging-0.4.9.2/README.txt tools/python/logging/logging-0.4.9.2/default.css tools/python/logging/logging-0.4.9.2/liblogging.tex tools/python/logging/logging-0.4.9.2/logging/__init__.py tools/python/logging/logging-0.4.9.2/logging/config.py tools/python/logging/logging-0.4.9.2/logging/handlers.py tools/python/logging/logging-0.4.9.2/python_logging.html tools/python/logging/logging-0.4.9.2/setup.py tools/python/logging/logging-0.4.9.2/test/app.py tools/python/logging/logging-0.4.9.2/test/critical.ini tools/python/logging/logging-0.4.9.2/test/debug.ini tools/python/logging/logging-0.4.9.2/test/error.ini tools/python/logging/logging-0.4.9.2/test/events.xml tools/python/logging/logging-0.4.9.2/test/log_test.py tools/python/logging/logging-0.4.9.2/test/log_test0.py tools/python/logging/logging-0.4.9.2/test/log_test1.py tools/python/logging/logging-0.4.9.2/test/log_test10.py tools/python/logging/logging-0.4.9.2/test/log_test11.py tools/python/logging/logging-0.4.9.2/test/log_test12.py tools/python/logging/logging-0.4.9.2/test/log_test13.py tools/python/logging/logging-0.4.9.2/test/log_test14.py tools/python/logging/logging-0.4.9.2/test/log_test15.py tools/python/logging/logging-0.4.9.2/test/log_test16.py tools/python/logging/logging-0.4.9.2/test/log_test17.py tools/python/logging/logging-0.4.9.2/test/log_test18.py tools/python/logging/logging-0.4.9.2/test/log_test19.py tools/python/logging/logging-0.4.9.2/test/log_test2.py tools/python/logging/logging-0.4.9.2/test/log_test20.py tools/python/logging/logging-0.4.9.2/test/log_test21.py tools/python/logging/logging-0.4.9.2/test/log_test22.py tools/python/logging/logging-0.4.9.2/test/log_test3.ini tools/python/logging/logging-0.4.9.2/test/log_test3.py tools/python/logging/logging-0.4.9.2/test/log_test4.py tools/python/logging/logging-0.4.9.2/test/log_test5.py tools/python/logging/logging-0.4.9.2/test/log_test6.py tools/python/logging/logging-0.4.9.2/test/log_test7.py tools/python/logging/logging-0.4.9.2/test/log_test8.py tools/python/logging/logging-0.4.9.2/test/log_test9.py tools/python/logging/logging-0.4.9.2/test/logconf.ini tools/python/logging/logging-0.4.9.2/test/logconf.py tools/python/logging/logging-0.4.9.2/test/logging.dtd tools/python/logging/logging-0.4.9.2/test/logging.xml tools/python/logging/logging-0.4.9.2/test/logrecv.ini tools/python/logging/logging-0.4.9.2/test/logrecv.py tools/python/logging/logging-0.4.9.2/test/myapp.py tools/python/logging/logging-0.4.9.2/test/mymodule.py tools/python/logging/logging-0.4.9.2/test/stderr.exp tools/python/logging/logging-0.4.9.2/test/stdout.exp tools/python/logging/logging-0.4.9.2/test/warn.ini tools/python/logging/setup.py tools/python/setup.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/XendLogging.py tools/python/xen/xend/XendRoot.py tools/python/xen/xend/server/SrvDaemon.py tools/python/xen/xend/server/blkif.py tools/python/xen/xend/server/console.py tools/python/xen/xend/server/domain.py tools/python/xen/xend/server/netif.py tools/python/xen/xend/server/params.py
line diff
     1.1 --- a/.rootkeys	Wed Jul 21 15:41:08 2004 +0000
     1.2 +++ b/.rootkeys	Thu Jul 22 13:42:39 2004 +0000
     1.3 @@ -311,6 +311,57 @@ 40c9c4697z76HDfkCLdMhmaEwzFoNQ tools/mis
     1.4  4056f5155QYZdsk-1fLdjsZPFTnlhg tools/misc/xensymoops.py
     1.5  40cf2937dqM1jWW87O5OoOYND8leuA tools/misc/xm
     1.6  40c9c468icGyC5RAF1bRKsCXPDCvsA tools/python/Makefile
     1.7 +40ffc44dOwe1CcYXGCkYHdG_NxcccA tools/python/logging/logging-0.4.9.2/PKG-INFO
     1.8 +40ffc44dpqpgqgrnLfR70PsiBc3liA tools/python/logging/logging-0.4.9.2/README.txt
     1.9 +40ffc44ddfLckno4Gvzi3vZxwelZHQ tools/python/logging/logging-0.4.9.2/default.css
    1.10 +40ffc44dKSkczdvpd_x7rWGH4_BRIQ tools/python/logging/logging-0.4.9.2/liblogging.tex
    1.11 +40ffc44d2O51abh5t-1VTZfqhbS1ZQ tools/python/logging/logging-0.4.9.2/logging/__init__.py
    1.12 +40ffc44dT8ustodG0hDjYMCzQ8UCbA tools/python/logging/logging-0.4.9.2/logging/config.py
    1.13 +40ffc44dqbwdCcq6XgwpTvrUrABhhw tools/python/logging/logging-0.4.9.2/logging/handlers.py
    1.14 +40ffc44dVEL3QwvZx_Rcl3d41WxMRQ tools/python/logging/logging-0.4.9.2/python_logging.html
    1.15 +40ffc44dXypIfRTyuTD48cN0o-gAXg tools/python/logging/logging-0.4.9.2/setup.py
    1.16 +40ffc44dqqdkY-Ox_eoPuNmQR0_ebw tools/python/logging/logging-0.4.9.2/test/app.py
    1.17 +40ffc44d9vEJEV_44B-23sJHkT1-gA tools/python/logging/logging-0.4.9.2/test/critical.ini
    1.18 +40ffc44dA5BiSVip8DlCh0DfAaQzbg tools/python/logging/logging-0.4.9.2/test/debug.ini
    1.19 +40ffc44dAuxUnJx7Fu2puaiNheBRkg tools/python/logging/logging-0.4.9.2/test/error.ini
    1.20 +40ffc44dkAIw1gbAzj_XiQyoru93_Q tools/python/logging/logging-0.4.9.2/test/events.xml
    1.21 +40ffc44eZwnQ4wGs1zVaAGsnEoyz6Q tools/python/logging/logging-0.4.9.2/test/log_test.py
    1.22 +40ffc44epbz06Y2nCkuYotfQFY4bJQ tools/python/logging/logging-0.4.9.2/test/log_test0.py
    1.23 +40ffc44eVNdi9lXQOZ2n7yT1DXVQRQ tools/python/logging/logging-0.4.9.2/test/log_test1.py
    1.24 +40ffc44eeqydHPpipbO4oVhRt90v0A tools/python/logging/logging-0.4.9.2/test/log_test10.py
    1.25 +40ffc44eSum6e6Y_sh7hRBHnnRurfw tools/python/logging/logging-0.4.9.2/test/log_test11.py
    1.26 +40ffc44euWPhfnbZw64ShBIrZot84A tools/python/logging/logging-0.4.9.2/test/log_test12.py
    1.27 +40ffc44ekj8Hdg-2SLb0qdqJzGkXdA tools/python/logging/logging-0.4.9.2/test/log_test13.py
    1.28 +40ffc44e5DnmO4OEa54mS8Q9AgP3rg tools/python/logging/logging-0.4.9.2/test/log_test14.py
    1.29 +40ffc44e6uWMQdikNEzYeNeFewGQew tools/python/logging/logging-0.4.9.2/test/log_test15.py
    1.30 +40ffc44eHJ_XsDp2Le-qc96G2n7GdQ tools/python/logging/logging-0.4.9.2/test/log_test16.py
    1.31 +40ffc44eCIq8wSc2UI16VfkLPlW-SQ tools/python/logging/logging-0.4.9.2/test/log_test17.py
    1.32 +40ffc44eHWycPlgiEpt8pE8xYTbUkg tools/python/logging/logging-0.4.9.2/test/log_test18.py
    1.33 +40ffc44eeRuZcrB3tQzfrQnh22NBow tools/python/logging/logging-0.4.9.2/test/log_test19.py
    1.34 +40ffc44e6jQPP-ASsVux4-ERGuDrmQ tools/python/logging/logging-0.4.9.2/test/log_test2.py
    1.35 +40ffc44eNHf6r77J1VCNedKPTufY8Q tools/python/logging/logging-0.4.9.2/test/log_test20.py
    1.36 +40ffc44emS2gplqyEwbcLS43QNrnyA tools/python/logging/logging-0.4.9.2/test/log_test21.py
    1.37 +40ffc44e1Ojd79zACM2KAnXZyO3Nuw tools/python/logging/logging-0.4.9.2/test/log_test22.py
    1.38 +40ffc44ektXcwDnK4h4HqMHFSTA3BA tools/python/logging/logging-0.4.9.2/test/log_test3.ini
    1.39 +40ffc44e8ka-b5_nPYzWn0hXDSagMw tools/python/logging/logging-0.4.9.2/test/log_test3.py
    1.40 +40ffc44eVmFkQt7FaHxspmMV7IZLxw tools/python/logging/logging-0.4.9.2/test/log_test4.py
    1.41 +40ffc44eYJ7tjlUpS5bIF9I8YKK39g tools/python/logging/logging-0.4.9.2/test/log_test5.py
    1.42 +40ffc44eo9GvB3GvC2Aoaxu74ffS4A tools/python/logging/logging-0.4.9.2/test/log_test6.py
    1.43 +40ffc44eajjKGx6tj2nOVuYCfy-PoA tools/python/logging/logging-0.4.9.2/test/log_test7.py
    1.44 +40ffc44eEM_uMfIGRNoxRSP7_jpc7w tools/python/logging/logging-0.4.9.2/test/log_test8.py
    1.45 +40ffc44e4NBnAweOds3owURsSHZKyQ tools/python/logging/logging-0.4.9.2/test/log_test9.py
    1.46 +40ffc44eu_SYlzJ464qUFb8fdSGHsg tools/python/logging/logging-0.4.9.2/test/logconf.ini
    1.47 +40ffc44eTnvlvCSmjgGgfcOBm6SSAw tools/python/logging/logging-0.4.9.2/test/logconf.py
    1.48 +40ffc44egchRehfcmsPX0WdV06yp_w tools/python/logging/logging-0.4.9.2/test/logging.dtd
    1.49 +40ffc44ee9peTFswy96mwgBslmqEvQ tools/python/logging/logging-0.4.9.2/test/logging.xml
    1.50 +40ffc44ekRTWScJDGTe7k2aAp_ltRg tools/python/logging/logging-0.4.9.2/test/logrecv.ini
    1.51 +40ffc44eeQBA_QbbwrucZfYtksuEMA tools/python/logging/logging-0.4.9.2/test/logrecv.py
    1.52 +40ffc44eECASCQD_QL3wJd4dyK2KVg tools/python/logging/logging-0.4.9.2/test/myapp.py
    1.53 +40ffc44eUwKMOAwPTIBq0A8N8b56HQ tools/python/logging/logging-0.4.9.2/test/mymodule.py
    1.54 +40ffc44evyvayldKLSsizMmsDpBtkQ tools/python/logging/logging-0.4.9.2/test/stderr.exp
    1.55 +40ffc44eb-39RIR551oZoTiK11amSw tools/python/logging/logging-0.4.9.2/test/stdout.exp
    1.56 +40ffc44eGvzBilqBZEozKaMHz-HdxA tools/python/logging/logging-0.4.9.2/test/warn.ini
    1.57 +40ffc44eLXLuINsYi8eG0oJ6a2dSRA tools/python/logging/setup.py
    1.58  40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/python/setup.py
    1.59  40dc4076hGpwa8-sWRN0jtXZeQJuKg tools/python/xen/__init__.py
    1.60  40dfd40aMOhnw_cQLve9462UR5yYxQ tools/python/xen/lowlevel/__init__.py
    1.61 @@ -336,6 +387,7 @@ 40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/pyt
    1.62  40c9c468bbKq3uC7_fuNUkiMMjArdw tools/python/xen/xend/XendDomainConfig.py
    1.63  40c9c4685ykq87_n1kVUbMr9flx9fg tools/python/xen/xend/XendDomainInfo.py
    1.64  40f50d99YiiaMI1fZBh1VCDFLD57qg tools/python/xen/xend/XendError.py
    1.65 +40ffc44eGsgTEY355E3nN4mPLZHhMQ tools/python/xen/xend/XendLogging.py
    1.66  40c9c46854nsHmuxHQHncKk5rAs5NA tools/python/xen/xend/XendMigrate.py
    1.67  40c9c468M96gA1EYDvNa5w5kQNYLFA tools/python/xen/xend/XendNode.py
    1.68  40c9c4686jruMyZIqiaZRMiMoqMJtg tools/python/xen/xend/XendRoot.py
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/python/logging/logging-0.4.9.2/PKG-INFO	Thu Jul 22 13:42:39 2004 +0000
     2.3 @@ -0,0 +1,25 @@
     2.4 +Metadata-Version: 1.0
     2.5 +Name: logging
     2.6 +Version: 0.4.9.2
     2.7 +Summary: A logging module for Python
     2.8 +Home-page: http://www.red-dove.com/python_logging.html
     2.9 +Author: Vinay Sajip
    2.10 +Author-email: vinay_sajip@red-dove.com
    2.11 +License: Copyright (C) 2001-2004 by Vinay Sajip. All Rights Reserved.
    2.12 +
    2.13 +Permission to use, copy, modify, and distribute this software and its
    2.14 +documentation for any purpose and without fee is hereby granted,
    2.15 +provided that the above copyright notice appear in all copies and that
    2.16 +both that copyright notice and this permission notice appear in
    2.17 +supporting documentation, and that the name of Vinay Sajip
    2.18 +not be used in advertising or publicity pertaining to distribution
    2.19 +of the software without specific, written prior permission.
    2.20 +
    2.21 +VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    2.22 +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
    2.23 +VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
    2.24 +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    2.25 +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
    2.26 +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    2.27 +Description: This module is intended to provide a standard error logging mechanism in Python as per PEP 282.
    2.28 +Platform: UNKNOWN
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/python/logging/logging-0.4.9.2/README.txt	Thu Jul 22 13:42:39 2004 +0000
     3.3 @@ -0,0 +1,311 @@
     3.4 +This module is intended to provide error logging functionality for Python
     3.5 +programs. It aims to be aligned with Python Enhancement Proposal (PEP) 282.
     3.6 +
     3.7 +For more information on the package itself, see python_logging.html. In it,
     3.8 +there is a description of each file in the distribution.
     3.9 +You can also use pydoc to browse the interfaces.
    3.10 +
    3.11 +Change History
    3.12 +--------------
    3.13 +
    3.14 +Version   Date        Description
    3.15 +=============================================================================
    3.16 +0.4.9.2   28 Feb 2004 Traceback text is now cached.
    3.17 +                      Tracebacks can be propagated across sockets as text.
    3.18 +                      Added makeLogRecord() to allow a LogRecord to be
    3.19 +                      created from a dictionary.
    3.20 +                      Closing a handler now removes it from the internal list
    3.21 +                      used by shutdown().
    3.22 +                      Made close() call flush() for handlers where this makes
    3.23 +                      sense (thanks to Jim Jewett).
    3.24 +                      The exc_info keyword parameter can be used to pass an
    3.25 +                      exception tuple as well as a flag indicating that the
    3.26 +                      current exception should be logged.
    3.27 +                      A shutdown hook is registered to call shutdown() on
    3.28 +                      application (Python) exit (thanks to Jim Jewett).
    3.29 +                      Removed redundant error check in setLoggerClass().
    3.30 +                      Added RESET_ERROR to logging.config.
    3.31 +                      SocketHandler now uses an exponential backoff strategy
    3.32 +                      (thanks to Robert Olson).
    3.33 +                      Minor documentation corrections.
    3.34 +-----------------------------------------------------------------------------
    3.35 +0.4.8     22 Apr 2003 Made _listener global in stopListening().
    3.36 +                      Made listen() correctly pass the specified port.
    3.37 +                      Removed some redundant imports in __init__.py.
    3.38 +                      Added the record being processed as a parameter to
    3.39 +                      handleError (thanks to Gordon den Otter for the idea).
    3.40 +                      Handler.handle returns the result of applying the
    3.41 +                      filter to the record (thanks to Gordon den Otter for
    3.42 +                      the idea).
    3.43 +                      Added a seek(0, 2) in RotatingFileHandler before the
    3.44 +                      tell() call. This is because under Windows, tell()
    3.45 +                      returns 0 until the first actual write (thanks to
    3.46 +                      Gordon den Otter for the patch).
    3.47 +                      Altered findCaller to not use inspect (thanks to
    3.48 +                      Jeremy Hylton for the patch).
    3.49 +                      Renamed warn and WARN to warning and WARNING. This may
    3.50 +                      break existing code, but the standard Python module
    3.51 +                      will use warning/WARNING rather than warn/WARN. The
    3.52 +                      fatal and FATAL synonyms for critical and CRITICAL
    3.53 +                      have also been removed.
    3.54 +                      Added defaultEncoding and some support for encoding
    3.55 +                      Unicode messages (thanks to Stéphane Bidoul for the
    3.56 +                      suggestion).
    3.57 +                      Added process ID to the list of LogRecord attributes.
    3.58 +                      Modified Logger.removeHandler so that it does not
    3.59 +                      close the handler on removal.
    3.60 +                      Modified SMTPHandler to treat a single "to address"
    3.61 +                      correctly (thanks to Anthony Baxter).
    3.62 +                      Modified SMTPHandler to add a date header to the SMTP
    3.63 +                      message (thanks to David Driver for the suggestion).
    3.64 +                      Modified HTTPHandler to factor out the mapping of
    3.65 +                      a LogRecord to a dictionary (thanks to Franz Glasner
    3.66 +                      for the patch).
    3.67 +-----------------------------------------------------------------------------
    3.68 +0.4.7     15 Nov 2002 Made into a package with three modules: __init__ (the
    3.69 +                      core code), handlers (all handlers other than
    3.70 +                      FileHandler and its bases) and config (all the config
    3.71 +                      stuff). Before doing this:
    3.72 +                      Updated docstrings to include a short line, then a
    3.73 +                      blank line, then more descriptive text.
    3.74 +                      Renamed 'lvl' to 'level' in various functions.
    3.75 +                      Changed FileHandler to use "a" and "w" instead of "a+"
    3.76 +                      and "w+".
    3.77 +                      Moved log file rotation functionality from FileHandler
    3.78 +                      to a new class RotatingFileHandler.
    3.79 +                      Improved docstring describing rollover.
    3.80 +                      Updated makePickle to use 4-byte length and struct
    3.81 +                      module, likewise logrecv.py. Also updated on-the-fly
    3.82 +                      config reader to use 4-byte length/struct module.
    3.83 +                      Altered ConfigParser test to look at 'readline' rather
    3.84 +                      than 'read'.
    3.85 +                      Added optional "defaults" argument to fileConfig, to
    3.86 +                      be passed to ConfigParser.
    3.87 +                      Renamed ALL to NOTSET to avoid confusion.
    3.88 +                      Commented out getRootLogger(), as obsolete.
    3.89 +                      To do regression testing, run log_test.py and compare
    3.90 +                      the created files stdout.log and stderr.log against
    3.91 +                      the files stdout.exp and stderr.exp. They should match
    3.92 +                      except fir a couple of exception messages which give
    3.93 +                      absolute file paths.
    3.94 +                      Updated python_logging.html to remove links to
    3.95 +                      logging_pydoc.html, which has been removed from the
    3.96 +                      distribution.
    3.97 +                      Changed default for raiseExceptions to 1.
    3.98 +-----------------------------------------------------------------------------
    3.99 +0.4.6     08 Jul 2002 Added raiseExceptions to allow conditional propagation
   3.100 +                      of exceptions which occur during handling.
   3.101 +                      Added converter to Formatter to allow use of any
   3.102 +                      function to convert time from seconds to a tuple. It
   3.103 +                      still defaults to time.localtime but now you can also
   3.104 +                      use time.gmtime.
   3.105 +                      Added log_test22.py to test the conversion feature.
   3.106 +                      Changed rootlogger default level to WARN - was DEBUG.
   3.107 +                      Updated some docstrings.
   3.108 +                      Moved import of threading to where thread is imported.
   3.109 +                      If either is unavailable, threading support is off.
   3.110 +                      Updated minor defects in python_logging.html.
   3.111 +                      Check to see if ConfigParser has readfp method; if it
   3.112 +                      does and an object with a 'read' method is passed in,
   3.113 +                      assumes a file-like object and uses readfp to read it
   3.114 +                      in.
   3.115 +-----------------------------------------------------------------------------
   3.116 +0.4.5     04 Jun 2002 Fixed bug which caused problem if no args to message
   3.117 +                      (suggested by Hye-Shik Chang).
   3.118 +                      Fixed bug in _fixupParents (thanks to Nicholas Veeser)
   3.119 +                      and added log_test19.py as a test case for this bug.
   3.120 +                      Added getMessage to LogRecord (code was moved here from
   3.121 +                      Formatter.format)
   3.122 +                      Applied str() to record.msg to allow arbitrary classes
   3.123 +                      to determine the formatting (as msg can now be a class
   3.124 +                      instance).
   3.125 +                      Table of Contents added to python_logging.html, the
   3.126 +                      section on Loggers updated, and the logconf.ini file
   3.127 +                      section annotated.
   3.128 +                      Added log_test20.py which demonstrates how to use
   3.129 +                      class instances to provide alternatives to numeric
   3.130 +                      severities as mechanisms for control of logging.
   3.131 +                      Added log_test21.py which builds on log_test20.py to
   3.132 +                      show how you can use a regular expression-based Filter
   3.133 +                      for flexible matching similar to e.g. Protomatter
   3.134 +                      Syslog, where you can filter on e.g. "a.*" or "*.b" or
   3.135 +                      "a.*.c".
   3.136 +                      _levelNames changed to contain reverse mappings as well
   3.137 +                      as forward mappings (leveltext->level as well as level
   3.138 +                      -> leveltext). The reverse mappings are used by
   3.139 +                      fileConfig().
   3.140 +                      fileConfig() now more forgiving of missing options in
   3.141 +                      .ini file - sensible defaults now used when some
   3.142 +                      options are absent. Also, eval() is used less when
   3.143 +                      interpreting .ini file contents - int() and dict lookup
   3.144 +                      are used in more places.
   3.145 +-----------------------------------------------------------------------------
   3.146 +0.4.4     02 May 2002 getEffectiveLevel() returns ALL instead of None when
   3.147 +                      nothing found. Modified references to level=0 to
   3.148 +                      level=ALL in a couple of places.
   3.149 +                      SocketHandler now inherits from Handler (it used to
   3.150 +                      inherit from StreamHandler, for no good reason).
   3.151 +                      getLock() renamed to createLock().
   3.152 +                      Docstring tidy-ups, and some tidying up of
   3.153 +                      DatagramHandler.
   3.154 +                      Factored out unpickling in logrecv.py.
   3.155 +                      Added log_test18.py to illustrate MatchFilter, which is
   3.156 +                      a general matching filter.
   3.157 +                      Improved FileHandler.doRollover() so that the base
   3.158 +                      file name is always the most recent, then .1, then .2
   3.159 +                      etc. up to the maximum backup count. Renamed formal
   3.160 +                      args and attributes used in rollover.
   3.161 +                      Changed LogRecord attributes lvl -> levelno, level ->
   3.162 +                      levelname (less ambiguity)
   3.163 +                      Formatter.format searches for "%(asctime)" rather than
   3.164 +                      "(asctime)"
   3.165 +                      Renamed _start_time to _startTime
   3.166 +                      Formatter.formatTime now returns the time
   3.167 +                      Altered logrecv.py to support stopping servers
   3.168 +                      programmatically
   3.169 +                      Added log_test.py as overall test harness
   3.170 +                      basicConfig() can now be safely called more than once
   3.171 +                      Modified test scripts to make it easier to call them
   3.172 +                      from log_test.py
   3.173 +                      Moved SOAPHandler from core to log_test13.py. It's not
   3.174 +                      general enough to be in the core; most production use
   3.175 +                      will have differing RPC signatures.
   3.176 +-----------------------------------------------------------------------------
   3.177 +0.4.3     14 Apr 2002 Bug fix one-off error message to go to sys.stderr
   3.178 +                      rather than sys.stdout.
   3.179 +                      logrecv.py fix TCP for busy network.
   3.180 +                      Thread safety - added locking to Handler and for shared
   3.181 +                      data in module, and log_test16.py to test it.
   3.182 +                      Added socket listener to allow on-the-fly configuration
   3.183 +                      and added log_test17.py to test it.
   3.184 +-----------------------------------------------------------------------------
   3.185 +0.4.2     11 Apr 2002 Bug fix fileConfig() - setup of MemoryHandler target
   3.186 +                      and errors when loggers have no handlers set or
   3.187 +                      handlers have no formatters set
   3.188 +                      logconf.py - seems to hang if window closed when combo
   3.189 +                      dropdown is showing - added code to close popup on exit
   3.190 +                      Some tweaks to _srcfile computation (normpath added)
   3.191 +                      findCaller() optimized, now a lot faster!
   3.192 +                      Logger.removeHandler now closes the handler before
   3.193 +                      removing it
   3.194 +                      fileConfig() removes existing handlers before adding
   3.195 +                      the new set, to avoid memory leakage when repeated
   3.196 +                      calls are made
   3.197 +                      Fixed logrecv.py bug which hogged CPU time when TCP
   3.198 +                      connection was closed from the client
   3.199 +                      Added log_test14.py to demonstrate/test a DBHandler
   3.200 +                      which writes logging records into an RDBMS using the
   3.201 +                      Python Database API 2.0 (to run, you need something
   3.202 +                      which supports this already installed - I tested with
   3.203 +                      mxODBC)
   3.204 +                      Made getLogger name argument optional - returns root
   3.205 +                      logger if omitted
   3.206 +                      Altered Filter to take a string initializer, filtering
   3.207 +                      a sub-hierarchy rooted at a particular point (idea from
   3.208 +                      Denis S. Otkidach).
   3.209 +                      Added log_test15.py to test Filter initializer
   3.210 +                      Minor docstring changes
   3.211 +-----------------------------------------------------------------------------
   3.212 +0.4.1     03 Apr 2002 Bug fix SMTPHandler - extra \r\n needed (Oleg Orlov)
   3.213 +                      Added BufferingHandler, BufferingFormatter
   3.214 +                      Renamed getChainedPriority to getEffectiveLevel
   3.215 +                      Removed Logger.getRoot as it is redundant
   3.216 +                      Added log_test9.py to test Buffering classes and
   3.217 +                      to show an XMLFormatter example.
   3.218 +                      Added setLoggerClass.
   3.219 +                      Added log_test10.py to test setLoggerClass, using an
   3.220 +                      example Logger-derived class which outputs exception
   3.221 +                      info even for DEBUG level logging calls
   3.222 +                      Added log_test11.py to test a buffering implementation
   3.223 +                      of SMTPHandler
   3.224 +                      Changed logging call implementation to allow keyword
   3.225 +                      arguments (Kevin Butler and others)
   3.226 +                      Changed default SysLogHandler implementation.
   3.227 +                      Renamed "additive" to "propagate" as it better
   3.228 +                      describes the attribute.
   3.229 +                      Added HTTPHandler.
   3.230 +                      Modified logrecv.py to remove "both" option and to add
   3.231 +                      "HTTP" and "SOAP" options (SOAP option needs you to
   3.232 +                      have PyXML-0.6.6 and ZSI installed - for logrecv.py
   3.233 +                      only, and not for the core logging module itself).
   3.234 +                      Added log_test12.py to test HTTPHandler.
   3.235 +                      Added log_test13.py to test SOAPHandler.
   3.236 +                      Formatted to Python source guidelines (spaces, indent
   3.237 +                      of 4, within 80 columns).
   3.238 +                      More method renamings (result of feedback) - _handle()
   3.239 +                      renamed to emit(), _logRecord() renamed to handle().
   3.240 +                      Renamed FATAL to CRITICAL (David Goodger), but left
   3.241 +                      fatal() and FATAL in (until PEP is changed)
   3.242 +                      Changed configuration file format to ConfigParser
   3.243 +                      format.
   3.244 +                      Factored filter application functionality out to a new
   3.245 +                      Filterer class. The isLoggable() method is renamed to
   3.246 +                      filter() in both Filter and Filterer classes.
   3.247 +                      Altered SMTPHandler __init__ to accept (host, port)
   3.248 +                      for the mail internet address.
   3.249 +                      Added GUI configurator which uses Tkinter and the new
   3.250 +                      configuration file format. (See logconf.py and an
   3.251 +                      example configuration file in logconf.ini)
   3.252 +                      Altered log_test3.py to test with the new file format.
   3.253 +-----------------------------------------------------------------------------
   3.254 +0.4       21 Mar 2002 Incorporated comments/patches from Ollie Rutherfurd:
   3.255 +                      -Added level filtering for handlers.
   3.256 +                      -Return root logger if no name specified in getLogger.
   3.257 +                      Incorporated comments from Greg Ward:
   3.258 +                      -Added distutils setup.py script.
   3.259 +                      Added formatter initialization in Handler.__init__.
   3.260 +                      Tidied up docstrings.
   3.261 +                      Added removeHandler to Logger.
   3.262 +                      Added removeFilter to Logger and Handler.
   3.263 +                      logrecv.py modified to keep connection alive until
   3.264 +                      client closes it.
   3.265 +                      SocketHandler modified to not reset connection after
   3.266 +                      each logging event.
   3.267 +                      Added shutdown function which closes open sockets
   3.268 +                      Renamed DEFAULT_LOGGING_PORT->DEFAULT_TCP_LOGGING_PORT
   3.269 +                      Added DEFAULT_UDP_LOGGING_PORT
   3.270 +                      Added log_test4.py (example of arbitrary levels)
   3.271 +                      Added addLevelName, changed behaviour of getLevelName
   3.272 +                      Fixed bugs in DatagramHandler
   3.273 +                      Added SMTPHandler implementation
   3.274 +                      Added log_test5.py to test SMTPHandler
   3.275 +                      Added SysLogHandler (contribution from Nicolas Untz
   3.276 +                      based on Sam Rushing's syslog.py)
   3.277 +                      Modified log_test1.py to add a SysLogHandler
   3.278 +                      Added rollover functionality to FileHandler
   3.279 +                      Added NTEventLogHandler (based on Win32 extensions)
   3.280 +                      Added MemoryHandler implementation
   3.281 +                      Added log_test7.py to test MemoryHandler
   3.282 +                      Added log_test8.py to test FileHandler rollover
   3.283 +                      Added logException method to Logger
   3.284 +                      Added formatException method to Formatter
   3.285 +                      Added log_test6.py to test NTEventHandler and
   3.286 +                      logException
   3.287 +                      Numerous internal method renamings (sorry - but better
   3.288 +                      to do this now, rather than when we enter beta status).
   3.289 +-----------------------------------------------------------------------------
   3.290 +0.3       14 Mar 2002 First public release, for early feedback
   3.291 +-----------------------------------------------------------------------------
   3.292 +0.2                   Consolidated into single file (for internal use only)
   3.293 +-----------------------------------------------------------------------------
   3.294 +0.1                   Initial implementation (for internal use only)
   3.295 +-----------------------------------------------------------------------------
   3.296 +
   3.297 +-----------------------------------------------------------------------------
   3.298 +COPYRIGHT
   3.299 +-----------------------------------------------------------------------------
   3.300 +Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
   3.301 +
   3.302 +Permission to use, copy, modify, and distribute this software and its
   3.303 +documentation for any purpose and without fee is hereby granted,
   3.304 +provided that the above copyright notice appear in all copies and that
   3.305 +both that copyright notice and this permission notice appear in
   3.306 +supporting documentation, and that the name of Vinay Sajip
   3.307 +not be used in advertising or publicity pertaining to distribution
   3.308 +of the software without specific, written prior permission.
   3.309 +VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   3.310 +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   3.311 +VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   3.312 +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
   3.313 +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
   3.314 +IN CONNECTION WITH THE USE OR PERFORMANCE	OF THIS SOFTWARE.
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/python/logging/logging-0.4.9.2/default.css	Thu Jul 22 13:42:39 2004 +0000
     4.3 @@ -0,0 +1,32 @@
     4.4 +BODY, P, UL, OL {font-family: Verdana, Arial, Helvetica, Geneva, sans-serif ; background: white; color: black; font-size: 10pt; }
     4.5 +CODE {font-family: "Courier New", Courier, Monaco, monospace ; }
     4.6 +PRE {font-family: "Courier New", Courier, Monaco, monospace ; }
     4.7 +.program { color: navy; font-family: "Courier New", Courier, Monaco, monospace }
     4.8 +.output { color: maroon }
     4.9 +HR {color: gray ; }
    4.10 +.navbar { font-family: Verdana, Arial, Helvetica, Geneva, sans-serif; background: #FFFF66 ; border-style: none none solid none; border-width: thin; padding: 2px;}
    4.11 +.navarea { background: #FFFF66 ; }
    4.12 +TR { font-size: 10pt }
    4.13 +.red { color: #FF0000 }
    4.14 +.maroon { color: #800000 }
    4.15 +.comment { color: green }
    4.16 +.optional { color: silver }
    4.17 +.strong { font-weight: bold }
    4.18 +TR.tblheading { background: silver ; }
    4.19 +.notrecommended {color: #666666 ; }
    4.20 +.deemphasized {color: #666666 ; }
    4.21 +TABLE.densetable {font-size: 80% ; }
    4.22 +TH { text-align: left; background: silver }
    4.23 +TR.summaryrow { font-size: 90%; background: #00FFFF ; }
    4.24 +CAPTION {font-size: 100% ; }
    4.25 +.embeddedfloat {float: right; margin-left: 3em}
    4.26 +.bigtd { font-size: 18pt }
    4.27 +TD, .normaltd { vertical-align: top; background: #EEEEEE; font-family: Verdana, Arial, Helvetica, Geneva, sans-serif; font-size: 10pt }
    4.28 +H1, H2, H3, H4, H5, H6 {font-family: Verdana, Arial, Helvetica, Geneva, sans-serif ; }
    4.29 +H4 {margin-bottom: 0.5em }
    4.30 +H5, H6 {margin-bottom: 0.1em }
    4.31 +A:link {color: blue ; }
    4.32 +A:visited {color: purple ; }
    4.33 +A:active {color: red ; }
    4.34 +A { font-family: Verdana, Arial, Helvetica, Geneva, sans-serif; font-size: 10pt }
    4.35 +.warning { color: red }
    4.36 \ No newline at end of file
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/python/logging/logging-0.4.9.2/liblogging.tex	Thu Jul 22 13:42:39 2004 +0000
     5.3 @@ -0,0 +1,1281 @@
     5.4 +\section{\module{logging} ---
     5.5 +         Logging facility for Python}
     5.6 +
     5.7 +\declaremodule{standard}{logging}
     5.8 +
     5.9 +% These apply to all modules, and may be given more than once:
    5.10 +
    5.11 +\moduleauthor{Vinay Sajip}{vinay_sajip@red-dove.com}
    5.12 +\sectionauthor{Vinay Sajip}{vinay_sajip@red-dove.com}
    5.13 +
    5.14 +\modulesynopsis{Logging module for Python based on \pep{282}.}
    5.15 +
    5.16 +\indexii{Errors}{logging}
    5.17 +
    5.18 +\versionadded{2.3}
    5.19 +This module defines functions and classes which implement a flexible
    5.20 +error logging system for applications.
    5.21 +
    5.22 +Logging is performed by calling methods on instances of the
    5.23 +\class{Logger} class (hereafter called \dfn{loggers}). Each instance has a
    5.24 +name, and they are conceptually arranged in a name space hierarchy
    5.25 +using dots (periods) as separators. For example, a logger named
    5.26 +"scan" is the parent of loggers "scan.text", "scan.html" and "scan.pdf".
    5.27 +Logger names can be anything you want, and indicate the area of an
    5.28 +application in which a logged message originates.
    5.29 +
    5.30 +Logged messages also have levels of importance associated with them.
    5.31 +The default levels provided are \constant{DEBUG}, \constant{INFO},
    5.32 +\constant{WARNING}, \constant{ERROR} and \constant{CRITICAL}. As a
    5.33 +convenience, you indicate the importance of a logged message by calling
    5.34 +an appropriate method of \class{Logger}. The methods are
    5.35 +\method{debug()}, \method{info()}, \method{warning()}, \method{error()} and
    5.36 +\method{critical()}, which mirror the default levels. You are not
    5.37 +constrained to use these levels: you can specify your own and use a
    5.38 +more general \class{Logger} method, \method{log()}, which takes an
    5.39 +explicit level argument.
    5.40 +
    5.41 +Levels can also be associated with loggers, being set either by the
    5.42 +developer or through loading a saved logging configuration. When a
    5.43 +logging method is called on a logger, the logger compares its own
    5.44 +level with the level associated with the method call. If the logger's
    5.45 +level is higher than the method call's, no logging message is actually
    5.46 +generated. This is the basic mechanism controlling the verbosity of
    5.47 +logging output.
    5.48 +
    5.49 +Logging messages are encoded as instances of the \class{LogRecord} class.
    5.50 +When a logger decides to actually log an event, an \class{LogRecord}
    5.51 +instance is created from the logging message.
    5.52 +
    5.53 +Logging messages are subjected to a dispatch mechanism through the
    5.54 +use of \dfn{handlers}, which are instances of subclasses of the
    5.55 +\class{Handler} class. Handlers are responsible for ensuring that a logged
    5.56 +message (in the form of a \class{LogRecord}) ends up in a particular
    5.57 +location (or set of locations) which is useful for the target audience for
    5.58 +that message (such as end users, support desk staff, system administrators,
    5.59 +developers). Handlers are passed \class{LogRecord} instances intended for
    5.60 +particular destinations. Each logger can have zero, one or more handlers
    5.61 +associated with it (via the \method{addHandler} method of \class{Logger}).
    5.62 +In addition to any handlers directly associated with a logger,
    5.63 +\emph{all handlers associated with all ancestors of the logger} are
    5.64 +called to dispatch the message.
    5.65 +
    5.66 +Just as for loggers, handlers can have levels associated with them.
    5.67 +A handler's level acts as a filter in the same way as a logger's level does.
    5.68 +If a handler decides to actually dispatch an event, the \method{emit()} method
    5.69 +is used to send the message to its destination. Most user-defined subclasses
    5.70 +of \class{Handler} will need to override this \method{emit()}.
    5.71 +
    5.72 +In addition to the base \class{Handler} class, many useful subclasses
    5.73 +are provided:
    5.74 +
    5.75 +\begin{enumerate}
    5.76 +
    5.77 +\item \class{StreamHandler} instances send error messages to
    5.78 +streams (file-like objects).
    5.79 +
    5.80 +\item \class{FileHandler} instances send error messages to disk
    5.81 +files.
    5.82 +
    5.83 +\item \class{RotatingFileHandler} instances send error messages to disk
    5.84 +files, with support for maximum log file sizes and log file rotation.
    5.85 +
    5.86 +\item \class{SocketHandler} instances send error messages to
    5.87 +TCP/IP sockets.
    5.88 +
    5.89 +\item \class{DatagramHandler} instances send error messages to UDP
    5.90 +sockets.
    5.91 +
    5.92 +\item \class{SMTPHandler} instances send error messages to a
    5.93 +designated email address.
    5.94 +
    5.95 +\item \class{SysLogHandler} instances send error messages to a
    5.96 +\UNIX{} syslog daemon, possibly on a remote machine.
    5.97 +
    5.98 +\item \class{NTEventLogHandler} instances send error messages to a
    5.99 +Windows NT/2000/XP event log.
   5.100 +
   5.101 +\item \class{MemoryHandler} instances send error messages to a
   5.102 +buffer in memory, which is flushed whenever specific criteria are
   5.103 +met.
   5.104 +
   5.105 +\item \class{HTTPHandler} instances send error messages to an
   5.106 +HTTP server using either \samp{GET} or \samp{POST} semantics.
   5.107 +
   5.108 +\end{enumerate}
   5.109 +
   5.110 +The \class{StreamHandler} and \class{FileHandler} classes are defined
   5.111 +in the core logging package. The other handlers are defined in a sub-
   5.112 +module, \module{logging.handlers}. (There is also another sub-module,
   5.113 +\module{logging.config}, for configuration functionality.)
   5.114 +
   5.115 +Logged messages are formatted for presentation through instances of the
   5.116 +\class{Formatter} class. They are initialized with a format string
   5.117 +suitable for use with the \% operator and a dictionary.
   5.118 +
   5.119 +For formatting multiple messages in a batch, instances of
   5.120 +\class{BufferingFormatter} can be used. In addition to the format string
   5.121 +(which is applied to each message in the batch), there is provision for
   5.122 +header and trailer format strings.
   5.123 +
   5.124 +When filtering based on logger level and/or handler level is not enough,
   5.125 +instances of \class{Filter} can be added to both \class{Logger} and
   5.126 +\class{Handler} instances (through their \method{addFilter()} method).
   5.127 +Before deciding to process a message further, both loggers and handlers
   5.128 +consult all their filters for permission. If any filter returns a false
   5.129 +value, the message is not processed further.
   5.130 +
   5.131 +The basic \class{Filter} functionality allows filtering by specific logger
   5.132 +name. If this feature is used, messages sent to the named logger and its
   5.133 +children are allowed through the filter, and all others dropped.
   5.134 +
   5.135 +In addition to the classes described above, there are a number of module-
   5.136 +level functions.
   5.137 +
   5.138 +\begin{funcdesc}{getLogger}{\optional{name}}
   5.139 +Return a logger with the specified name or, if no name is specified, return
   5.140 +a logger which is the root logger of the hierarchy.
   5.141 +
   5.142 +All calls to this function with a given name return the same logger instance.
   5.143 +This means that logger instances never need to be passed between different
   5.144 +parts of an application.
   5.145 +\end{funcdesc}
   5.146 +
   5.147 +\begin{funcdesc}{debug}{msg\optional{, *args\optional{, **kwargs}}}
   5.148 +Logs a message with level \constant{DEBUG} on the root logger.
   5.149 +The \var{msg} is the message format string, and the \var{args} are the
   5.150 +arguments which are merged into \var{msg}. The only keyword argument in
   5.151 +\var{kwargs} which is inspected is \var{exc_info} which, if it does not
   5.152 +evaluate as false, causes exception information (via a call to
   5.153 +\function{sys.exc_info()}) to be added to the logging message.
   5.154 +\end{funcdesc}
   5.155 +
   5.156 +\begin{funcdesc}{info}{msg\optional{, *args\optional{, **kwargs}}}
   5.157 +Logs a message with level \constant{INFO} on the root logger.
   5.158 +The arguments are interpreted as for \function{debug()}.
   5.159 +\end{funcdesc}
   5.160 +
   5.161 +\begin{funcdesc}{warning}{msg\optional{, *args\optional{, **kwargs}}}
   5.162 +Logs a message with level \constant{WARNING} on the root logger.
   5.163 +The arguments are interpreted as for \function{debug()}.
   5.164 +\end{funcdesc}
   5.165 +
   5.166 +\begin{funcdesc}{error}{msg\optional{, *args\optional{, **kwargs}}}
   5.167 +Logs a message with level \constant{ERROR} on the root logger.
   5.168 +The arguments are interpreted as for \function{debug()}.
   5.169 +\end{funcdesc}
   5.170 +
   5.171 +\begin{funcdesc}{critical}{msg\optional{, *args\optional{, **kwargs}}}
   5.172 +Logs a message with level \constant{CRITICAL} on the root logger.
   5.173 +The arguments are interpreted as for \function{debug()}.
   5.174 +\end{funcdesc}
   5.175 +
   5.176 +\begin{funcdesc}{exception}{msg\optional{, *args}}
   5.177 +Logs a message with level \constant{ERROR} on the root logger.
   5.178 +The arguments are interpreted as for \function{debug()}. Exception info
   5.179 +is added to the logging message. This function should only be called
   5.180 +from an exception handler.
   5.181 +\end{funcdesc}
   5.182 +
   5.183 +\begin{funcdesc}{disable}{lvl}
   5.184 +Provides an overriding level \var{lvl} for all loggers which takes
   5.185 +precedence over the logger's own level. When the need arises to
   5.186 +temporarily throttle logging output down across the whole application,
   5.187 +this function can be useful.
   5.188 +\end{funcdesc}
   5.189 +
   5.190 +\begin{funcdesc}{addLevelName}{lvl, levelName}
   5.191 +Associates level \var{lvl} with text \var{levelName} in an internal
   5.192 +dictionary, which is used to map numeric levels to a textual
   5.193 +representation, for example when a \class{Formatter} formats a message.
   5.194 +This function can also be used to define your own levels. The only
   5.195 +constraints are that all levels used must be registered using this
   5.196 +function, levels should be positive integers and they should increase
   5.197 +in increasing order of severity.
   5.198 +\end{funcdesc}
   5.199 +
   5.200 +\begin{funcdesc}{getLevelName}{lvl}
   5.201 +Returns the textual representation of logging level \var{lvl}. If the
   5.202 +level is one of the predefined levels \constant{CRITICAL},
   5.203 +\constant{ERROR}, \constant{WARNING}, \constant{INFO} or \constant{DEBUG}
   5.204 +then you get the corresponding string. If you have associated levels
   5.205 +with names using \function{addLevelName()} then the name you have associated
   5.206 +with \var{lvl} is returned. Otherwise, the string "Level \%s" \% lvl is
   5.207 +returned.
   5.208 +\end{funcdesc}
   5.209 +
   5.210 +\begin{funcdesc}{makeLogRecord}{attrdict}
   5.211 +Creates and returns a new \class{LogRecord} instance whose attributes are
   5.212 +defined by \var{attrdict}. This function is useful for taking a pickled
   5.213 +\class{LogRecord} attribute dictionary, sent over a socket, and reconstituting
   5.214 +it as a \class{LogRecord} instance at the receiving end.
   5.215 +\end{funcdesc}
   5.216 +
   5.217 +\begin{funcdesc}{basicConfig}{}
   5.218 +Does basic configuration for the logging system by creating a
   5.219 +\class{StreamHandler} with a default \class{Formatter} and adding it to
   5.220 +the root logger. The functions \function{debug()}, \function{info()},
   5.221 +\function{warning()}, \function{error()} and \function{critical()} will call
   5.222 +\function{basicConfig()} automatically if no handlers are defined for the
   5.223 +root logger.
   5.224 +\end{funcdesc}
   5.225 +
   5.226 +\begin{funcdesc}{shutdown}{}
   5.227 +Informs the logging system to perform an orderly shutdown by flushing and
   5.228 +closing all handlers.
   5.229 +\end{funcdesc}
   5.230 +
   5.231 +\begin{funcdesc}{setLoggerClass}{klass}
   5.232 +Tells the logging system to use the class \var{klass} when instantiating a
   5.233 +logger. The class should define \method{__init__()} such that only a name
   5.234 +argument is required, and the \method{__init__()} should call
   5.235 +\method{Logger.__init__()}. This function is typically called before any
   5.236 +loggers are instantiated by applications which need to use custom logger
   5.237 +behavior.
   5.238 +\end{funcdesc}
   5.239 +
   5.240 +
   5.241 +\begin{seealso}
   5.242 +  \seepep{282}{A Logging System}
   5.243 +         {The proposal which described this feature for inclusion in
   5.244 +          the Python standard library.}
   5.245 +  \seelink{http://www.red-dove.com/python_logging.html}
   5.246 +          {Original Python \module{logging} package}
   5.247 +          {This is the original source for the \module{logging}
   5.248 +           package.  The version of the package available from this
   5.249 +           site is suitable for use with Python 1.5.2, 2.1.x and 2.2.x, which
   5.250 +           do not include the \module{logging} package in the standard
   5.251 +           library.}
   5.252 +\end{seealso}
   5.253 +
   5.254 +
   5.255 +\subsection{Logger Objects}
   5.256 +
   5.257 +Loggers have the following attributes and methods. Note that Loggers are
   5.258 +never instantiated directly, but always through the module-level function
   5.259 +\function{logging.getLogger(name)}.
   5.260 +
   5.261 +\begin{datadesc}{propagate}
   5.262 +If this evaluates to false, logging messages are not passed by this
   5.263 +logger or by child loggers to higher level (ancestor) loggers. The
   5.264 +constructor sets this attribute to 1.
   5.265 +\end{datadesc}
   5.266 +
   5.267 +\begin{methoddesc}{setLevel}{lvl}
   5.268 +Sets the threshold for this logger to \var{lvl}. Logging messages
   5.269 +which are less severe than \var{lvl} will be ignored. When a logger is
   5.270 +created, the level is set to \constant{NOTSET} (which causes all messages
   5.271 +to be processed in the root logger, or delegation to the parent in non-root
   5.272 +loggers).
   5.273 +\end{methoddesc}
   5.274 +
   5.275 +\begin{methoddesc}{isEnabledFor}{lvl}
   5.276 +Indicates if a message of severity \var{lvl} would be processed by
   5.277 +this logger.  This method checks first the module-level level set by
   5.278 +\function{logging.disable(lvl)} and then the logger's effective level as
   5.279 +determined by \method{getEffectiveLevel()}.
   5.280 +\end{methoddesc}
   5.281 +
   5.282 +\begin{methoddesc}{getEffectiveLevel}{}
   5.283 +Indicates the effective level for this logger. If a value other than
   5.284 +\constant{NOTSET} has been set using \method{setLevel()}, it is returned.
   5.285 +Otherwise, the hierarchy is traversed towards the root until a value
   5.286 +other than \constant{NOTSET} is found, and that value is returned.
   5.287 +\end{methoddesc}
   5.288 +
   5.289 +\begin{methoddesc}{debug}{msg\optional{, *args\optional{, **kwargs}}}
   5.290 +Logs a message with level \constant{DEBUG} on this logger.
   5.291 +The \var{msg} is the message format string, and the \var{args} are the
   5.292 +arguments which are merged into \var{msg}. The only keyword argument in
   5.293 +\var{kwargs} which is inspected is \var{exc_info} which, if it does not
   5.294 +evaluate as false, causes exception information (via a call to
   5.295 +\function{sys.exc_info()}) to be added to the logging message.
   5.296 +\end{methoddesc}
   5.297 +
   5.298 +\begin{methoddesc}{info}{msg\optional{, *args\optional{, **kwargs}}}
   5.299 +Logs a message with level \constant{INFO} on this logger.
   5.300 +The arguments are interpreted as for \method{debug()}.
   5.301 +\end{methoddesc}
   5.302 +
   5.303 +\begin{methoddesc}{warning}{msg\optional{, *args\optional{, **kwargs}}}
   5.304 +Logs a message with level \constant{WARNING} on this logger.
   5.305 +The arguments are interpreted as for \method{debug()}.
   5.306 +\end{methoddesc}
   5.307 +
   5.308 +\begin{methoddesc}{error}{msg\optional{, *args\optional{, **kwargs}}}
   5.309 +Logs a message with level \constant{ERROR} on this logger.
   5.310 +The arguments are interpreted as for \method{debug()}.
   5.311 +\end{methoddesc}
   5.312 +
   5.313 +\begin{methoddesc}{critical}{msg\optional{, *args\optional{, **kwargs}}}
   5.314 +Logs a message with level \constant{CRITICAL} on this logger.
   5.315 +The arguments are interpreted as for \method{debug()}.
   5.316 +\end{methoddesc}
   5.317 +
   5.318 +\begin{methoddesc}{log}{lvl, msg\optional{, *args\optional{, **kwargs}}}
   5.319 +Logs a message with level \var{lvl} on this logger.
   5.320 +The other arguments are interpreted as for \method{debug()}.
   5.321 +\end{methoddesc}
   5.322 +
   5.323 +\begin{methoddesc}{exception}{msg\optional{, *args}}
   5.324 +Logs a message with level \constant{ERROR} on this logger.
   5.325 +The arguments are interpreted as for \method{debug()}. Exception info
   5.326 +is added to the logging message. This method should only be called
   5.327 +from an exception handler.
   5.328 +\end{methoddesc}
   5.329 +
   5.330 +\begin{methoddesc}{addFilter}{filt}
   5.331 +Adds the specified filter \var{filt} to this logger.
   5.332 +\end{methoddesc}
   5.333 +
   5.334 +\begin{methoddesc}{removeFilter}{filt}
   5.335 +Removes the specified filter \var{filt} from this logger.
   5.336 +\end{methoddesc}
   5.337 +
   5.338 +\begin{methoddesc}{filter}{record}
   5.339 +Applies this logger's filters to the record and returns a true value if
   5.340 +the record is to be processed.
   5.341 +\end{methoddesc}
   5.342 +
   5.343 +\begin{methoddesc}{addHandler}{hdlr}
   5.344 +Adds the specified handler \var{hdlr} to this logger.
   5.345 +\end{methoddesc}
   5.346 +
   5.347 +\begin{methoddesc}{removeHandler}{hdlr}
   5.348 +Removes the specified handler \var{hdlr} from this logger.
   5.349 +\end{methoddesc}
   5.350 +
   5.351 +\begin{methoddesc}{findCaller}{}
   5.352 +Finds the caller's source filename and line number. Returns the filename
   5.353 +and line number as a 2-element tuple.
   5.354 +\end{methoddesc}
   5.355 +
   5.356 +\begin{methoddesc}{handle}{record}
   5.357 +Handles a record by passing it to all handlers associated with this logger
   5.358 +and its ancestors (until a false value of \var{propagate} is found).
   5.359 +This method is used for unpickled records received from a socket, as well
   5.360 +as those created locally. Logger-level filtering is applied using
   5.361 +\method{filter()}.
   5.362 +\end{methoddesc}
   5.363 +
   5.364 +\begin{methoddesc}{makeRecord}{name, lvl, fn, lno, msg, args, exc_info}
   5.365 +This is a factory method which can be overridden in subclasses to create
   5.366 +specialized \class{LogRecord} instances.
   5.367 +\end{methoddesc}
   5.368 +
   5.369 +\subsection{Handler Objects}
   5.370 +
   5.371 +Handlers have the following attributes and methods. Note that
   5.372 +\class{Handler} is never instantiated directly; this class acts as a
   5.373 +base for more useful subclasses. However, the \method{__init__()}
   5.374 +method in subclasses needs to call \method{Handler.__init__()}.
   5.375 +
   5.376 +\begin{methoddesc}{__init__}{level=\constant{NOTSET}}
   5.377 +Initializes the \class{Handler} instance by setting its level, setting
   5.378 +the list of filters to the empty list and creating a lock (using
   5.379 +\method{createLock()}) for serializing access to an I/O mechanism.
   5.380 +\end{methoddesc}
   5.381 +
   5.382 +\begin{methoddesc}{createLock}{}
   5.383 +Initializes a thread lock which can be used to serialize access to
   5.384 +underlying I/O functionality which may not be threadsafe.
   5.385 +\end{methoddesc}
   5.386 +
   5.387 +\begin{methoddesc}{acquire}{}
   5.388 +Acquires the thread lock created with \method{createLock()}.
   5.389 +\end{methoddesc}
   5.390 +
   5.391 +\begin{methoddesc}{release}{}
   5.392 +Releases the thread lock acquired with \method{acquire()}.
   5.393 +\end{methoddesc}
   5.394 +
   5.395 +\begin{methoddesc}{setLevel}{lvl}
   5.396 +Sets the threshold for this handler to \var{lvl}. Logging messages which are
   5.397 +less severe than \var{lvl} will be ignored. When a handler is created, the
   5.398 +level is set to \constant{NOTSET} (which causes all messages to be processed).
   5.399 +\end{methoddesc}
   5.400 +
   5.401 +\begin{methoddesc}{setFormatter}{form}
   5.402 +Sets the \class{Formatter} for this handler to \var{form}.
   5.403 +\end{methoddesc}
   5.404 +
   5.405 +\begin{methoddesc}{addFilter}{filt}
   5.406 +Adds the specified filter \var{filt} to this handler.
   5.407 +\end{methoddesc}
   5.408 +
   5.409 +\begin{methoddesc}{removeFilter}{filt}
   5.410 +Removes the specified filter \var{filt} from this handler.
   5.411 +\end{methoddesc}
   5.412 +
   5.413 +\begin{methoddesc}{filter}{record}
   5.414 +Applies this handler's filters to the record and returns a true value if
   5.415 +the record is to be processed.
   5.416 +\end{methoddesc}
   5.417 +
   5.418 +\begin{methoddesc}{flush}{}
   5.419 +Ensure all logging output has been flushed. This version does
   5.420 +nothing and is intended to be implemented by subclasses.
   5.421 +\end{methoddesc}
   5.422 +
   5.423 +\begin{methoddesc}{close}{}
   5.424 +Tidy up any resources used by the handler. This version does
   5.425 +nothing and is intended to be implemented by subclasses.
   5.426 +\end{methoddesc}
   5.427 +
   5.428 +\begin{methoddesc}{handle}{record}
   5.429 +Conditionally emits the specified logging record, depending on
   5.430 +filters which may have been added to the handler. Wraps the actual
   5.431 +emission of the record with acquisition/release of the I/O thread
   5.432 +lock.
   5.433 +\end{methoddesc}
   5.434 +
   5.435 +\begin{methoddesc}{handleError}{record}
   5.436 +This method should be called from handlers when an exception is
   5.437 +encountered during an \method{emit()} call. By default it does nothing,
   5.438 +which means that exceptions get silently ignored. This is what is
   5.439 +mostly wanted for a logging system - most users will not care
   5.440 +about errors in the logging system, they are more interested in
   5.441 +application errors. You could, however, replace this with a custom
   5.442 +handler if you wish. The specified record is the one which was being
   5.443 +processed when the exception occurred.
   5.444 +\end{methoddesc}
   5.445 +
   5.446 +\begin{methoddesc}{format}{record}
   5.447 +Do formatting for a record - if a formatter is set, use it.
   5.448 +Otherwise, use the default formatter for the module.
   5.449 +\end{methoddesc}
   5.450 +
   5.451 +\begin{methoddesc}{emit}{record}
   5.452 +Do whatever it takes to actually log the specified logging record.
   5.453 +This version is intended to be implemented by subclasses and so
   5.454 +raises a \exception{NotImplementedError}.
   5.455 +\end{methoddesc}
   5.456 +
   5.457 +\subsubsection{StreamHandler}
   5.458 +
   5.459 +The \class{StreamHandler} class sends logging output to streams such as
   5.460 +\var{sys.stdout}, \var{sys.stderr} or any file-like object (or, more
   5.461 +precisely, any object which supports \method{write()} and \method{flush()}
   5.462 +methods).
   5.463 +
   5.464 +\begin{classdesc}{StreamHandler}{\optional{strm}}
   5.465 +Returns a new instance of the \class{StreamHandler} class. If \var{strm} is
   5.466 +specified, the instance will use it for logging output; otherwise,
   5.467 +\var{sys.stderr} will be used.
   5.468 +\end{classdesc}
   5.469 +
   5.470 +\begin{methoddesc}{emit}{record}
   5.471 +If a formatter is specified, it is used to format the record.
   5.472 +The record is then written to the stream with a trailing newline.
   5.473 +If exception information is present, it is formatted using
   5.474 +\function{traceback.print_exception()} and appended to the stream.
   5.475 +\end{methoddesc}
   5.476 +
   5.477 +\begin{methoddesc}{flush}{}
   5.478 +Flushes the stream by calling its \method{flush()} method. Note that
   5.479 +the \method{close()} method is inherited from \class{Handler} and
   5.480 +so does nothing, so an explicit \method{flush()} call may be needed
   5.481 +at times.
   5.482 +\end{methoddesc}
   5.483 +
   5.484 +\subsubsection{FileHandler}
   5.485 +
   5.486 +The \class{FileHandler} class sends logging output to a disk file.
   5.487 +It inherits the output functionality from \class{StreamHandler}.
   5.488 +
   5.489 +\begin{classdesc}{FileHandler}{filename\optional{, mode}}
   5.490 +Returns a new instance of the \class{FileHandler} class. The specified
   5.491 +file is opened and used as the stream for logging. If \var{mode} is
   5.492 +not specified, \constant{'a'} is used. By default, the file grows
   5.493 +indefinitely.
   5.494 +\end{classdesc}
   5.495 +
   5.496 +\begin{methoddesc}{close}{}
   5.497 +Closes the file.
   5.498 +\end{methoddesc}
   5.499 +
   5.500 +\begin{methoddesc}{emit}{record}
   5.501 +Outputs the record to the file.
   5.502 +\end{methoddesc}
   5.503 +
   5.504 +\subsubsection{RotatingFileHandler}
   5.505 +
   5.506 +The \class{RotatingFileHandler} class supports rotation of disk log files.
   5.507 +
   5.508 +\begin{classdesc}{RotatingFileHandler}{filename\optional{, mode\optional{,
   5.509 +                                       maxBytes\optional{, backupCount}}}}
   5.510 +Returns a new instance of the \class{RotatingFileHandler} class. The
   5.511 +specified file is opened and used as the stream for logging. If
   5.512 +\var{mode} is not specified, \code{'a'} is used. By default, the
   5.513 +file grows indefinitely.
   5.514 +
   5.515 +You can use the \var{maxBytes} and
   5.516 +\var{backupCount} values to allow the file to \dfn{rollover} at a
   5.517 +predetermined size. When the size is about to be exceeded, the file is
   5.518 +closed and a new file is silently opened for output. Rollover occurs
   5.519 +whenever the current log file is nearly \var{maxBytes} in length; if
   5.520 +\var{maxBytes} is zero, rollover never occurs.  If \var{backupCount}
   5.521 +is non-zero, the system will save old log files by appending the
   5.522 +extensions ".1", ".2" etc., to the filename. For example, with
   5.523 +a \var{backupCount} of 5 and a base file name of
   5.524 +\file{app.log}, you would get \file{app.log},
   5.525 +\file{app.log.1}, \file{app.log.2}, up to \file{app.log.5}. The file being
   5.526 +written to is always \file{app.log}.  When this file is filled, it is
   5.527 +closed and renamed to \file{app.log.1}, and if files \file{app.log.1},
   5.528 +\file{app.log.2}, etc.  exist, then they are renamed to \file{app.log.2},
   5.529 +\file{app.log.3} etc.  respectively.
   5.530 +\end{classdesc}
   5.531 +
   5.532 +\begin{methoddesc}{doRollover}{}
   5.533 +Does a rollover, as described above.
   5.534 +\end{methoddesc}
   5.535 +
   5.536 +\begin{methoddesc}{emit}{record}
   5.537 +Outputs the record to the file, catering for rollover as described
   5.538 +in \method{setRollover()}.
   5.539 +\end{methoddesc}
   5.540 +
   5.541 +\subsubsection{SocketHandler}
   5.542 +
   5.543 +The \class{SocketHandler} class sends logging output to a network
   5.544 +socket. The base class uses a TCP socket.
   5.545 +
   5.546 +\begin{classdesc}{SocketHandler}{host, port}
   5.547 +Returns a new instance of the \class{SocketHandler} class intended to
   5.548 +communicate with a remote machine whose address is given by \var{host}
   5.549 +and \var{port}.
   5.550 +\end{classdesc}
   5.551 +
   5.552 +\begin{methoddesc}{close}{}
   5.553 +Closes the socket.
   5.554 +\end{methoddesc}
   5.555 +
   5.556 +\begin{methoddesc}{handleError}{}
   5.557 +\end{methoddesc}
   5.558 +
   5.559 +\begin{methoddesc}{emit}{}
   5.560 +Pickles the record's attribute dictionary and writes it to the socket in
   5.561 +binary format. If there is an error with the socket, silently drops the
   5.562 +packet. If the connection was previously lost, re-establishes the connection.
   5.563 +To unpickle the record at the receiving end into a LogRecord, use the
   5.564 +\function{makeLogRecord} function.
   5.565 +\end{methoddesc}
   5.566 +
   5.567 +\begin{methoddesc}{handleError}{}
   5.568 +Handles an error which has occurred during \method{emit()}. The
   5.569 +most likely cause is a lost connection. Closes the socket so that
   5.570 +we can retry on the next event.
   5.571 +\end{methoddesc}
   5.572 +
   5.573 +\begin{methoddesc}{makeSocket}{}
   5.574 +This is a factory method which allows subclasses to define the precise
   5.575 +type of socket they want. The default implementation creates a TCP
   5.576 +socket (\constant{socket.SOCK_STREAM}).
   5.577 +\end{methoddesc}
   5.578 +
   5.579 +\begin{methoddesc}{makePickle}{record}
   5.580 +Pickles the record's attribute dictionary in binary format with a length
   5.581 +prefix, and returns it ready for transmission across the socket.
   5.582 +\end{methoddesc}
   5.583 +
   5.584 +\begin{methoddesc}{send}{packet}
   5.585 +Send a pickled string \var{packet} to the socket. This function allows
   5.586 +for partial sends which can happen when the network is busy.
   5.587 +\end{methoddesc}
   5.588 +
   5.589 +\subsubsection{DatagramHandler}
   5.590 +
   5.591 +The \class{DatagramHandler} class inherits from \class{SocketHandler}
   5.592 +to support sending logging messages over UDP sockets.
   5.593 +
   5.594 +\begin{classdesc}{DatagramHandler}{host, port}
   5.595 +Returns a new instance of the \class{DatagramHandler} class intended to
   5.596 +communicate with a remote machine whose address is given by \var{host}
   5.597 +and \var{port}.
   5.598 +\end{classdesc}
   5.599 +
   5.600 +\begin{methoddesc}{emit}{}
   5.601 +Pickles the record's attribute dictionary and writes it to the socket in
   5.602 +binary format. If there is an error with the socket, silently drops the
   5.603 +packet.
   5.604 +To unpickle the record at the receiving end into a LogRecord, use the
   5.605 +\function{makeLogRecord} function.
   5.606 +\end{methoddesc}
   5.607 +
   5.608 +\begin{methoddesc}{makeSocket}{}
   5.609 +The factory method of \class{SocketHandler} is here overridden to create
   5.610 +a UDP socket (\constant{socket.SOCK_DGRAM}).
   5.611 +\end{methoddesc}
   5.612 +
   5.613 +\begin{methoddesc}{send}{s}
   5.614 +Send a pickled string to a socket.
   5.615 +\end{methoddesc}
   5.616 +
   5.617 +\subsubsection{SysLogHandler}
   5.618 +
   5.619 +The \class{SysLogHandler} class supports sending logging messages to a
   5.620 +remote or local \UNIX{} syslog.
   5.621 +
   5.622 +\begin{classdesc}{SysLogHandler}{\optional{address\optional{, facility}}}
   5.623 +Returns a new instance of the \class{SysLogHandler} class intended to
   5.624 +communicate with a remote \UNIX{} machine whose address is given by
   5.625 +\var{address} in the form of a \code{(\var{host}, \var{port})}
   5.626 +tuple.  If \var{address} is not specified, \code{('localhost', 514)} is
   5.627 +used.  The address is used to open a UDP socket.  If \var{facility} is
   5.628 +not specified, \constant{LOG_USER} is used.
   5.629 +\end{classdesc}
   5.630 +
   5.631 +\begin{methoddesc}{close}{}
   5.632 +Closes the socket to the remote host.
   5.633 +\end{methoddesc}
   5.634 +
   5.635 +\begin{methoddesc}{emit}{record}
   5.636 +The record is formatted, and then sent to the syslog server. If
   5.637 +exception information is present, it is \emph{not} sent to the server.
   5.638 +\end{methoddesc}
   5.639 +
   5.640 +\begin{methoddesc}{encodePriority}{facility, priority}
   5.641 +Encodes the facility and priority into an integer. You can pass in strings
   5.642 +or integers - if strings are passed, internal mapping dictionaries are used
   5.643 +to convert them to integers.
   5.644 +\end{methoddesc}
   5.645 +
   5.646 +\subsubsection{NTEventLogHandler}
   5.647 +
   5.648 +The \class{NTEventLogHandler} class supports sending logging messages
   5.649 +to a local Windows NT, Windows 2000 or Windows XP event log. Before
   5.650 +you can use it, you need Mark Hammond's Win32 extensions for Python
   5.651 +installed.
   5.652 +
   5.653 +\begin{classdesc}{NTEventLogHandler}{appname\optional{,
   5.654 +                                     dllname\optional{, logtype}}}
   5.655 +Returns a new instance of the \class{NTEventLogHandler} class. The
   5.656 +\var{appname} is used to define the application name as it appears in the
   5.657 +event log. An appropriate registry entry is created using this name.
   5.658 +The \var{dllname} should give the fully qualified pathname of a .dll or .exe
   5.659 +which contains message definitions to hold in the log (if not specified,
   5.660 +\code{'win32service.pyd'} is used - this is installed with the Win32
   5.661 +extensions and contains some basic placeholder message definitions.
   5.662 +Note that use of these placeholders will make your event logs big, as the
   5.663 +entire message source is held in the log. If you want slimmer logs, you have
   5.664 +to pass in the name of your own .dll or .exe which contains the message
   5.665 +definitions you want to use in the event log). The \var{logtype} is one of
   5.666 +\code{'Application'}, \code{'System'} or \code{'Security'}, and
   5.667 +defaults to \code{'Application'}.
   5.668 +\end{classdesc}
   5.669 +
   5.670 +\begin{methoddesc}{close}{}
   5.671 +At this point, you can remove the application name from the registry as a
   5.672 +source of event log entries. However, if you do this, you will not be able
   5.673 +to see the events as you intended in the Event Log Viewer - it needs to be
   5.674 +able to access the registry to get the .dll name. The current version does
   5.675 +not do this (in fact it doesn't do anything).
   5.676 +\end{methoddesc}
   5.677 +
   5.678 +\begin{methoddesc}{emit}{record}
   5.679 +Determines the message ID, event category and event type, and then logs the
   5.680 +message in the NT event log.
   5.681 +\end{methoddesc}
   5.682 +
   5.683 +\begin{methoddesc}{getEventCategory}{record}
   5.684 +Returns the event category for the record. Override this if you
   5.685 +want to specify your own categories. This version returns 0.
   5.686 +\end{methoddesc}
   5.687 +
   5.688 +\begin{methoddesc}{getEventType}{record}
   5.689 +Returns the event type for the record. Override this if you want
   5.690 +to specify your own types. This version does a mapping using the
   5.691 +handler's typemap attribute, which is set up in \method{__init__()}
   5.692 +to a dictionary which contains mappings for \constant{DEBUG},
   5.693 +\constant{INFO}, \constant{WARNING}, \constant{ERROR} and
   5.694 +\constant{CRITICAL}. If you are using your own levels, you will either need
   5.695 +to override this method or place a suitable dictionary in the
   5.696 +handler's \var{typemap} attribute.
   5.697 +\end{methoddesc}
   5.698 +
   5.699 +\begin{methoddesc}{getMessageID}{record}
   5.700 +Returns the message ID for the record. If you are using your
   5.701 +own messages, you could do this by having the \var{msg} passed to the
   5.702 +logger being an ID rather than a format string. Then, in here,
   5.703 +you could use a dictionary lookup to get the message ID. This
   5.704 +version returns 1, which is the base message ID in
   5.705 +\file{win32service.pyd}.
   5.706 +\end{methoddesc}
   5.707 +
   5.708 +\subsubsection{SMTPHandler}
   5.709 +
   5.710 +The \class{SMTPHandler} class supports sending logging messages to an email
   5.711 +address via SMTP.
   5.712 +
   5.713 +\begin{classdesc}{SMTPHandler}{mailhost, fromaddr, toaddrs, subject}
   5.714 +Returns a new instance of the \class{SMTPHandler} class. The
   5.715 +instance is initialized with the from and to addresses and subject
   5.716 +line of the email. The \var{toaddrs} should be a list of strings without
   5.717 +domain names (That's what the \var{mailhost} is for). To specify a
   5.718 +non-standard SMTP port, use the (host, port) tuple format for the
   5.719 +\var{mailhost} argument. If you use a string, the standard SMTP port
   5.720 +is used.
   5.721 +\end{classdesc}
   5.722 +
   5.723 +\begin{methoddesc}{emit}{record}
   5.724 +Formats the record and sends it to the specified addressees.
   5.725 +\end{methoddesc}
   5.726 +
   5.727 +\begin{methoddesc}{getSubject}{record}
   5.728 +If you want to specify a subject line which is record-dependent,
   5.729 +override this method.
   5.730 +\end{methoddesc}
   5.731 +
   5.732 +\subsubsection{MemoryHandler}
   5.733 +
   5.734 +The \class{MemoryHandler} supports buffering of logging records in memory,
   5.735 +periodically flushing them to a \dfn{target} handler. Flushing occurs
   5.736 +whenever the buffer is full, or when an event of a certain severity or
   5.737 +greater is seen.
   5.738 +
   5.739 +\class{MemoryHandler} is a subclass of the more general
   5.740 +\class{BufferingHandler}, which is an abstract class. This buffers logging
   5.741 +records in memory. Whenever each record is added to the buffer, a
   5.742 +check is made by calling \method{shouldFlush()} to see if the buffer
   5.743 +should be flushed.  If it should, then \method{flush()} is expected to
   5.744 +do the needful.
   5.745 +
   5.746 +\begin{classdesc}{BufferingHandler}{capacity}
   5.747 +Initializes the handler with a buffer of the specified capacity.
   5.748 +\end{classdesc}
   5.749 +
   5.750 +\begin{methoddesc}{emit}{record}
   5.751 +Appends the record to the buffer. If \method{shouldFlush()} returns true,
   5.752 +calls \method{flush()} to process the buffer.
   5.753 +\end{methoddesc}
   5.754 +
   5.755 +\begin{methoddesc}{flush}{}
   5.756 +You can override this to implement custom flushing behavior. This version
   5.757 +just zaps the buffer to empty.
   5.758 +\end{methoddesc}
   5.759 +
   5.760 +\begin{methoddesc}{shouldFlush}{record}
   5.761 +Returns true if the buffer is up to capacity. This method can be
   5.762 +overridden to implement custom flushing strategies.
   5.763 +\end{methoddesc}
   5.764 +
   5.765 +\begin{classdesc}{MemoryHandler}{capacity\optional{, flushLevel
   5.766 +\optional{, target}}}
   5.767 +Returns a new instance of the \class{MemoryHandler} class. The
   5.768 +instance is initialized with a buffer size of \var{capacity}. If
   5.769 +\var{flushLevel} is not specified, \constant{ERROR} is used. If no
   5.770 +\var{target} is specified, the target will need to be set using
   5.771 +\method{setTarget()} before this handler does anything useful.
   5.772 +\end{classdesc}
   5.773 +
   5.774 +\begin{methoddesc}{close}{}
   5.775 +Calls \method{flush()}, sets the target to \constant{None} and
   5.776 +clears the buffer.
   5.777 +\end{methoddesc}
   5.778 +
   5.779 +\begin{methoddesc}{flush}{}
   5.780 +For a \class{MemoryHandler}, flushing means just sending the buffered
   5.781 +records to the target, if there is one. Override if you want
   5.782 +different behavior.
   5.783 +\end{methoddesc}
   5.784 +
   5.785 +\begin{methoddesc}{setTarget}{target}
   5.786 +Sets the target handler for this handler.
   5.787 +\end{methoddesc}
   5.788 +
   5.789 +\begin{methoddesc}{shouldFlush}{record}
   5.790 +Checks for buffer full or a record at the \var{flushLevel} or higher.
   5.791 +\end{methoddesc}
   5.792 +
   5.793 +\subsubsection{HTTPHandler}
   5.794 +
   5.795 +The \class{HTTPHandler} class supports sending logging messages to a
   5.796 +Web server, using either \samp{GET} or \samp{POST} semantics.
   5.797 +
   5.798 +\begin{classdesc}{HTTPHandler}{host, url\optional{, method}}
   5.799 +Returns a new instance of the \class{HTTPHandler} class. The
   5.800 +instance is initialized with a host address, url and HTTP method.
   5.801 +If no \var{method} is specified, \samp{GET} is used.
   5.802 +\end{classdesc}
   5.803 +
   5.804 +\begin{methoddesc}{emit}{record}
   5.805 +Sends the record to the Web server as an URL-encoded dictionary.
   5.806 +\end{methoddesc}
   5.807 +
   5.808 +\subsection{Formatter Objects}
   5.809 +
   5.810 +\class{Formatter}s have the following attributes and methods. They are
   5.811 +responsible for converting a \class{LogRecord} to (usually) a string
   5.812 +which can be interpreted by either a human or an external system. The
   5.813 +base
   5.814 +\class{Formatter} allows a formatting string to be specified. If none is
   5.815 +supplied, the default value of \code{'\%(message)s\e'} is used.
   5.816 +
   5.817 +A Formatter can be initialized with a format string which makes use of
   5.818 +knowledge of the \class{LogRecord} attributes - such as the default value
   5.819 +mentioned above making use of the fact that the user's message and
   5.820 +arguments are pre-formatted into a LogRecord's \var{message}
   5.821 +attribute.  This format string contains standard python \%-style
   5.822 +mapping keys. See section \ref{typesseq-strings}, ``String Formatting
   5.823 +Operations,'' for more information on string formatting.
   5.824 +
   5.825 +Currently, the useful mapping keys in a LogRecord are:
   5.826 +
   5.827 +\begin{tableii}{l|l}{code}{Format}{Description}
   5.828 +\lineii{\%(name)s}     {Name of the logger (logging channel).}
   5.829 +\lineii{\%(levelno)s}  {Numeric logging level for the message
   5.830 +                        (\constant{DEBUG}, \constant{INFO},
   5.831 +                        \constant{WARNING}, \constant{ERROR},
   5.832 +                        \constant{CRITICAL}).}
   5.833 +\lineii{\%(levelname)s}{Text logging level for the message
   5.834 +                        (\code{'DEBUG'}, \code{'INFO'},
   5.835 +                        \code{'WARNING'}, \code{'ERROR'},
   5.836 +                        \code{'CRITICAL'}).}
   5.837 +\lineii{\%(pathname)s} {Full pathname of the source file where the logging
   5.838 +                        call was issued (if available).}
   5.839 +\lineii{\%(filename)s} {Filename portion of pathname.}
   5.840 +\lineii{\%(module)s}   {Module (name portion of filename).}
   5.841 +\lineii{\%(lineno)d}   {Source line number where the logging call was issued
   5.842 +                        (if available).}
   5.843 +\lineii{\%(created)f}  {Time when the LogRecord was created (as
   5.844 +                        returned by \function{time.time()}).}
   5.845 +\lineii{\%(asctime)s}  {Human-readable time when the LogRecord was created.
   5.846 +                        By default this is of the form
   5.847 +                        ``2003-07-08 16:49:45,896'' (the numbers after the
   5.848 +                        comma are millisecond portion of the time).}
   5.849 +\lineii{\%(msecs)d}    {Millisecond portion of the time when the
   5.850 +                        \class{LogRecord} was created.}
   5.851 +\lineii{\%(thread)d}   {Thread ID (if available).}
   5.852 +\lineii{\%(process)d}  {Process ID (if available).}
   5.853 +\lineii{\%(message)s}  {The logged message, computed as \code{msg \% args}.}
   5.854 +\end{tableii}
   5.855 +
   5.856 +\begin{classdesc}{Formatter}{\optional{fmt\optional{, datefmt}}}
   5.857 +Returns a new instance of the \class{Formatter} class. The
   5.858 +instance is initialized with a format string for the message as a whole,
   5.859 +as well as a format string for the date/time portion of a message. If
   5.860 +no \var{fmt} is specified, \code{'\%(message)s'} is used. If no \var{datefmt}
   5.861 +is specified, the ISO8601 date format is used.
   5.862 +\end{classdesc}
   5.863 +
   5.864 +\begin{methoddesc}{format}{record}
   5.865 +The record's attribute dictionary is used as the operand to a
   5.866 +string formatting operation. Returns the resulting string.
   5.867 +Before formatting the dictionary, a couple of preparatory steps
   5.868 +are carried out. The \var{message} attribute of the record is computed
   5.869 +using \var{msg} \% \var{args}. If the formatting string contains
   5.870 +\code{'(asctime)'}, \method{formatTime()} is called to format the
   5.871 +event time. If there is exception information, it is formatted using
   5.872 +\method{formatException()} and appended to the message.
   5.873 +\end{methoddesc}
   5.874 +
   5.875 +\begin{methoddesc}{formatTime}{record\optional{, datefmt}}
   5.876 +This method should be called from \method{format()} by a formatter which
   5.877 +wants to make use of a formatted time. This method can be overridden
   5.878 +in formatters to provide for any specific requirement, but the
   5.879 +basic behavior is as follows: if \var{datefmt} (a string) is specified,
   5.880 +it is used with \function{time.strftime()} to format the creation time of the
   5.881 +record. Otherwise, the ISO8601 format is used. The resulting
   5.882 +string is returned.
   5.883 +\end{methoddesc}
   5.884 +
   5.885 +\begin{methoddesc}{formatException}{exc_info}
   5.886 +Formats the specified exception information (a standard exception tuple
   5.887 +as returned by \function{sys.exc_info()}) as a string. This default
   5.888 +implementation just uses \function{traceback.print_exception()}.
   5.889 +The resulting string is returned.
   5.890 +\end{methoddesc}
   5.891 +
   5.892 +\subsection{Filter Objects}
   5.893 +
   5.894 +\class{Filter}s can be used by \class{Handler}s and \class{Logger}s for
   5.895 +more sophisticated filtering than is provided by levels. The base filter
   5.896 +class only allows events which are below a certain point in the logger
   5.897 +hierarchy. For example, a filter initialized with "A.B" will allow events
   5.898 +logged by loggers "A.B", "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB",
   5.899 +"B.A.B" etc. If initialized with the empty string, all events are passed.
   5.900 +
   5.901 +\begin{classdesc}{Filter}{\optional{name}}
   5.902 +Returns an instance of the \class{Filter} class. If \var{name} is specified,
   5.903 +it names a logger which, together with its children, will have its events
   5.904 +allowed through the filter. If no name is specified, allows every event.
   5.905 +\end{classdesc}
   5.906 +
   5.907 +\begin{methoddesc}{filter}{record}
   5.908 +Is the specified record to be logged? Returns zero for no, nonzero for
   5.909 +yes. If deemed appropriate, the record may be modified in-place by this
   5.910 +method.
   5.911 +\end{methoddesc}
   5.912 +
   5.913 +\subsection{LogRecord Objects}
   5.914 +
   5.915 +LogRecord instances are created every time something is logged. They
   5.916 +contain all the information pertinent to the event being logged. The
   5.917 +main information passed in is in msg and args, which are combined
   5.918 +using msg \% args to create the message field of the record. The record
   5.919 +also includes information such as when the record was created, the
   5.920 +source line where the logging call was made, and any exception
   5.921 +information to be logged.
   5.922 +
   5.923 +LogRecord has no methods; it's just a repository for information about the
   5.924 +logging event. The only reason it's a class rather than a dictionary is to
   5.925 +facilitate extension.
   5.926 +
   5.927 +\begin{classdesc}{LogRecord}{name, lvl, pathname, lineno, msg, args,
   5.928 +                             exc_info}
   5.929 +Returns an instance of \class{LogRecord} initialized with interesting
   5.930 +information. The \var{name} is the logger name; \var{lvl} is the
   5.931 +numeric level; \var{pathname} is the absolute pathname of the source
   5.932 +file in which the logging call was made; \var{lineno} is the line
   5.933 +number in that file where the logging call is found; \var{msg} is the
   5.934 +user-supplied message (a format string); \var{args} is the tuple
   5.935 +which, together with \var{msg}, makes up the user message; and
   5.936 +\var{exc_info} is the exception tuple obtained by calling
   5.937 +\function{sys.exc_info() }(or \constant{None}, if no exception information
   5.938 +is available).
   5.939 +\end{classdesc}
   5.940 +
   5.941 +\subsection{Thread Safety}
   5.942 +
   5.943 +The logging module is intended to be thread-safe without any special work
   5.944 +needing to be done by its clients. It achieves this though using threading
   5.945 +locks; there is one lock to serialize access to the module's shared data,
   5.946 +and each handler also creates a lock to serialize access to its underlying
   5.947 +I/O.
   5.948 +
   5.949 +\subsection{Configuration}
   5.950 +
   5.951 +
   5.952 +\subsubsection{Configuration functions}
   5.953 +
   5.954 +The following functions allow the logging module to be
   5.955 +configured. Before they can be used, you must import
   5.956 +\module{logging.config}.  Their use is optional --- you can configure
   5.957 +the logging module entirely by making calls to the main API (defined
   5.958 +in \module{logging} itself) and defining handlers which are declared
   5.959 +either in \module{logging} or \module{logging.handlers}.
   5.960 +
   5.961 +\begin{funcdesc}{fileConfig}{fname\optional{, defaults}}
   5.962 +Reads the logging configuration from a ConfigParser-format file named
   5.963 +\var{fname}. This function can be called several times from an application,
   5.964 +allowing an end user the ability to select from various pre-canned
   5.965 +configurations (if the developer provides a mechanism to present the
   5.966 +choices and load the chosen configuration). Defaults to be passed to
   5.967 +ConfigParser can be specified in the \var{defaults} argument.
   5.968 +\end{funcdesc}
   5.969 +
   5.970 +\begin{funcdesc}{listen}{\optional{port}}
   5.971 +Starts up a socket server on the specified port, and listens for new
   5.972 +configurations. If no port is specified, the module's default
   5.973 +\constant{DEFAULT_LOGGING_CONFIG_PORT} is used. Logging configurations
   5.974 +will be sent as a file suitable for processing by \function{fileConfig()}.
   5.975 +Returns a \class{Thread} instance on which you can call \method{start()}
   5.976 +to start the server, and which you can \method{join()} when appropriate.
   5.977 +To stop the server, call \function{stopListening()}.
   5.978 +\end{funcdesc}
   5.979 +
   5.980 +\begin{funcdesc}{stopListening}{}
   5.981 +Stops the listening server which was created with a call to
   5.982 +\function{listen()}. This is typically called before calling \method{join()}
   5.983 +on the return value from \function{listen()}.
   5.984 +\end{funcdesc}
   5.985 +
   5.986 +\subsubsection{Configuration file format}
   5.987 +
   5.988 +The configuration file format understood by \function{fileConfig} is
   5.989 +based on ConfigParser functionality. The file must contain sections
   5.990 +called \code{[loggers]}, \code{[handlers]} and \code{[formatters]}
   5.991 +which identify by name the entities of each type which are defined in
   5.992 +the file. For each such entity, there is a separate section which
   5.993 +identified how that entity is configured. Thus, for a logger named
   5.994 +\code{log01} in the \code{[loggers]} section, the relevant
   5.995 +configuration details are held in a section
   5.996 +\code{[logger_log01]}. Similarly, a handler called \code{hand01} in
   5.997 +the \code{[handlers]} section will have its configuration held in a
   5.998 +section called \code{[handler_hand01]}, while a formatter called
   5.999 +\code{form01} in the \code{[formatters]} section will have its
  5.1000 +configuration specified in a section called
  5.1001 +\code{[formatter_form01]}. The root logger configuration must be
  5.1002 +specified in a section called \code{[logger_root]}.
  5.1003 +
  5.1004 +Examples of these sections in the file are given below.
  5.1005 +
  5.1006 +\begin{verbatim}
  5.1007 +[loggers]
  5.1008 +keys=root,log02,log03,log04,log05,log06,log07
  5.1009 +
  5.1010 +[handlers]
  5.1011 +keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09
  5.1012 +
  5.1013 +[formatters]
  5.1014 +keys=form01,form02,form03,form04,form05,form06,form07,form08,form09
  5.1015 +\end{verbatim}
  5.1016 +
  5.1017 +The root logger must specify a level and a list of handlers. An
  5.1018 +example of a root logger section is given below.
  5.1019 +
  5.1020 +\begin{verbatim}
  5.1021 +[logger_root]
  5.1022 +level=NOTSET
  5.1023 +handlers=hand01
  5.1024 +\end{verbatim}
  5.1025 +
  5.1026 +The \code{level} entry can be one of \code{DEBUG, INFO, WARNING,
  5.1027 +ERROR, CRITICAL} or \code{NOTSET}. For the root logger only,
  5.1028 +\code{NOTSET} means that all messages will be logged. Level values are
  5.1029 +\function{eval()}uated in the context of the \code{logging} package's
  5.1030 +namespace.
  5.1031 +
  5.1032 +The \code{handlers} entry is a comma-separated list of handler names,
  5.1033 +which must appear in the \code{[handlers]} section. These names must
  5.1034 +appear in the \code{[handlers]} section and have corresponding
  5.1035 +sections in the configuration file.
  5.1036 +
  5.1037 +For loggers other than the root logger, some additional information is
  5.1038 +required. This is illustrated by the following example.
  5.1039 +
  5.1040 +\begin{verbatim}
  5.1041 +[logger_parser]
  5.1042 +level=DEBUG
  5.1043 +handlers=hand01
  5.1044 +propagate=1
  5.1045 +qualname=compiler.parser
  5.1046 +\end{verbatim}
  5.1047 +
  5.1048 +The \code{level} and \code{handlers} entries are interpreted as for
  5.1049 +the root logger, except that if a non-root logger's level is specified
  5.1050 +as \code{NOTSET}, the system consults loggers higher up the hierarchy
  5.1051 +to determine the effective level of the logger. The \code{propagate}
  5.1052 +entry is set to 1 to indicate that messages must propagate to handlers
  5.1053 +higher up the logger hierarchy from this logger, or 0 to indicate that
  5.1054 +messages are \strong{not} propagated to handlers up the hierarchy. The
  5.1055 +\code{qualname} entry is the hierarchical channel name of the logger,
  5.1056 +that is to say the name used by the application to get the logger.
  5.1057 +
  5.1058 +Sections which specify handler configuration are exemplified by the
  5.1059 +following.
  5.1060 +
  5.1061 +\begin{verbatim}
  5.1062 +[handler_hand01]
  5.1063 +class=StreamHandler
  5.1064 +level=NOTSET
  5.1065 +formatter=form01
  5.1066 +args=(sys.stdout,)
  5.1067 +\end{verbatim}
  5.1068 +
  5.1069 +The \code{class} entry indicates the handler's class (as determined by
  5.1070 +\function{eval()} in the \code{logging} package's namespace). The
  5.1071 +\code{level} is interpreted as for loggers, and \code{NOTSET} is taken
  5.1072 +to mean "log everything".
  5.1073 +
  5.1074 +The \code{formatter} entry indicates the key name of the formatter for
  5.1075 +this handler. If blank, a default formatter
  5.1076 +(\code{logging._defaultFormatter}) is used. If a name is specified, it
  5.1077 +must appear in the \code{[formatters]} section and have a
  5.1078 +corresponding section in the configuration file.
  5.1079 +
  5.1080 +The \code{args} entry, when \function{eval()}uated in the context of
  5.1081 +the \code{logging} package's namespace, is the list of arguments to
  5.1082 +the constructor for the handler class. Refer to the constructors for
  5.1083 +the relevant handlers, or to the examples below, to see how typical
  5.1084 +entries are constructed.
  5.1085 +
  5.1086 +\begin{verbatim}
  5.1087 +[handler_hand02]
  5.1088 +class=FileHandler
  5.1089 +level=DEBUG
  5.1090 +formatter=form02
  5.1091 +args=('python.log', 'w')
  5.1092 +
  5.1093 +[handler_hand03]
  5.1094 +class=handlers.SocketHandler
  5.1095 +level=INFO
  5.1096 +formatter=form03
  5.1097 +args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)
  5.1098 +
  5.1099 +[handler_hand04]
  5.1100 +class=handlers.DatagramHandler
  5.1101 +level=WARN
  5.1102 +formatter=form04
  5.1103 +args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)
  5.1104 +
  5.1105 +[handler_hand05]
  5.1106 +class=handlers.SysLogHandler
  5.1107 +level=ERROR
  5.1108 +formatter=form05
  5.1109 +args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
  5.1110 +
  5.1111 +[handler_hand06]
  5.1112 +class=NTEventLogHandler
  5.1113 +level=CRITICAL
  5.1114 +formatter=form06
  5.1115 +args=('Python Application', '', 'Application')
  5.1116 +
  5.1117 +[handler_hand07]
  5.1118 +class=SMTPHandler
  5.1119 +level=WARN
  5.1120 +formatter=form07
  5.1121 +args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
  5.1122 +
  5.1123 +[handler_hand08]
  5.1124 +class=MemoryHandler
  5.1125 +level=NOTSET
  5.1126 +formatter=form08
  5.1127 +target=
  5.1128 +args=(10, ERROR)
  5.1129 +
  5.1130 +[handler_hand09]
  5.1131 +class=HTTPHandler
  5.1132 +level=NOTSET
  5.1133 +formatter=form09
  5.1134 +args=('localhost:9022', '/log', 'GET')
  5.1135 +\end{verbatim}
  5.1136 +
  5.1137 +Sections which specify formatter configuration are typified by the following.
  5.1138 +
  5.1139 +\begin{verbatim}
  5.1140 +[formatter_form01]
  5.1141 +format=F1 %(asctime)s %(levelname)s %(message)s
  5.1142 +datefmt=
  5.1143 +\end{verbatim}
  5.1144 +
  5.1145 +The \code{format} entry is the overall format string, and the
  5.1146 +\code{datefmt} entry is the \function{strftime()}-compatible date/time format
  5.1147 +string. If empty, the package substitutes ISO8601 format date/times, which
  5.1148 +is almost equivalent to specifying the date format string "%Y-%m-%d %H:%M:%S".
  5.1149 +The ISO8601 format also specifies milliseconds, which are appended to the
  5.1150 +result of using the above format string, with a comma separator. An example
  5.1151 +time in ISO8601 format is \code{2003-01-23 00:29:50,411}.
  5.1152 +
  5.1153 +\subsection{Using the logging package}
  5.1154 +
  5.1155 +\subsubsection{Simplest usage}
  5.1156 +
  5.1157 +Here's a simple example which shows the most casual usage of the logging
  5.1158 +package.
  5.1159 +
  5.1160 +\begin{verbatim}
  5.1161 +import logging
  5.1162 +logging.debug("Houston, we have a %s", "thorny problem")
  5.1163 +logging.info("Houston, we have a %s", "interesting problem")
  5.1164 +logging.warning("Houston, we have a %s", "bit of a problem")
  5.1165 +logging.error("Houston, we have a %s", "major problem")
  5.1166 +logging.critical("Houston, we have a %s", "major disaster")
  5.1167 +try:
  5.1168 +	infinity = 1 / 0
  5.1169 +except:
  5.1170 +	logging.exception("Houston, we have an %s", "unexpected problem")
  5.1171 +\end{verbatim}
  5.1172 +
  5.1173 +If you run the above example, this will produce:
  5.1174 +
  5.1175 +\begin{verbatim}
  5.1176 +WARNING:root:Houston, we have a bit of a problem
  5.1177 +ERROR:root:Houston, we have a major problem
  5.1178 +CRITICAL:root:Houston, we have a major disaster
  5.1179 +ERROR:root:Houston, we have an unexpected problem
  5.1180 +Traceback (most recent call last):
  5.1181 +  File "C:\Projects\RDC\Python\packages\logging\test\tmp.py", line 8, in ?
  5.1182 +    infinity = 1 / 0
  5.1183 +ZeroDivisionError: integer division or modulo by zero
  5.1184 +\end{verbatim}
  5.1185 +
  5.1186 +The reason you get this output is that the default format is
  5.1187 +
  5.1188 +\begin{verbatim}
  5.1189 +"%(levelname)s:%(name)s:%(message)s".
  5.1190 +\end{verbatim}
  5.1191 +
  5.1192 +When you invoke functions \function{info()}, \function{warning()} etc. in the
  5.1193 +logging package itself, these calls are delegated to the correspondingly
  5.1194 +named methods in the root logger. This is why the logger name shown in the above
  5.1195 +logging output is "root". If the root logger has no handlers configured, the
  5.1196 +logging package creates a console handler and adds it to the root logger
  5.1197 +automatically. (It does this by calling the \function{basicConfig()}, which you
  5.1198 +can also call directly from your own code.)
  5.1199 +
  5.1200 +By default, events with a severity below WARNING are suppressed. Notice
  5.1201 +that the \function{exception()} function acts like \function{error()}, except
  5.1202 +that a traceback is appended to the log entry.
  5.1203 +
  5.1204 +\subsubsection{Logging to the console}
  5.1205 +
  5.1206 +Here's a simple example which logs all messages to the console. We use a named
  5.1207 +logger:
  5.1208 +
  5.1209 +\begin{verbatim}
  5.1210 +import logging
  5.1211 +logging.basicConfig()
  5.1212 +logger = logging.getLogger('myapp')
  5.1213 +logger.setLevel(logging.DEBUG)
  5.1214 +logger.debug("Houston, we have a %s", "thorny problem")
  5.1215 +logger.info("Houston, we have a %s", "interesting problem")
  5.1216 +logger.warning("Houston, we have a %s", "bit of a problem")
  5.1217 +logger.error("Houston, we have a %s", "major problem")
  5.1218 +logger.critical("Houston, we have a %s", "major disaster")
  5.1219 +try:
  5.1220 +	infinity = 1 / 0
  5.1221 +except:
  5.1222 +	logger.exception("Houston, we have an %s", "unexpected problem")
  5.1223 +\end{verbatim}
  5.1224 +
  5.1225 +Here's the corresponding output:
  5.1226 +
  5.1227 +\begin{verbatim}
  5.1228 +DEBUG:myapp:Houston, we have a thorny problem
  5.1229 +INFO:myapp:Houston, we have a interesting problem
  5.1230 +WARNING:myapp:Houston, we have a bit of a problem
  5.1231 +ERROR:myapp:Houston, we have a major problem
  5.1232 +CRITICAL:myapp:Houston, we have a major disaster
  5.1233 +ERROR:myapp:Houston, we have an unexpected problem
  5.1234 +Traceback (most recent call last):
  5.1235 +  File "C:\Projects\RDC\Python\packages\logging\test\tmp.py", line 11, in ?
  5.1236 +    infinity = 1 / 0
  5.1237 +ZeroDivisionError: integer division or modulo by zero
  5.1238 +\end{verbatim}
  5.1239 +
  5.1240 +As you can see, the specified logger name now appears in the output, and
  5.1241 +DEBUG and INFO messages are included in the output because we explicitly
  5.1242 +asked for them via the call to \method{setLevel()}.
  5.1243 +
  5.1244 +\subsubsection{Logging to a file}
  5.1245 +
  5.1246 +Here's a simple logging example that just logs to a file. In order,
  5.1247 +it creates a \class{Logger} instance, then a \class{FileHandler}
  5.1248 +and a \class{Formatter}. It attaches the \class{Formatter} to the
  5.1249 +\class{FileHandler}, then the \class{FileHandler} to the \class{Logger}.
  5.1250 +Finally, it sets a debug level for the logger.
  5.1251 +
  5.1252 +\begin{verbatim}
  5.1253 +import logging
  5.1254 +logger = logging.getLogger('myapp')
  5.1255 +hdlr = logging.FileHandler('/var/tmp/myapp.log')
  5.1256 +formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
  5.1257 +hdlr.setFormatter(formatter)
  5.1258 +logger.addHandler(hdlr)
  5.1259 +logger.setLevel(logging.WARNING)
  5.1260 +\end{verbatim}
  5.1261 +
  5.1262 +We can use this logger object now to write entries to the log file:
  5.1263 +
  5.1264 +\begin{verbatim}
  5.1265 +logger.error('We have a problem')
  5.1266 +logger.info('While this is just chatty')
  5.1267 +\end{verbatim}
  5.1268 +
  5.1269 +If we look in the file that was created, we'll see something like this:
  5.1270 +\begin{verbatim}
  5.1271 +2003-07-08 16:49:45,896 ERROR We have a problem
  5.1272 +\end{verbatim}
  5.1273 +
  5.1274 +The info message was not written to the file - we called the \method{setLevel}
  5.1275 +method to say we only wanted \code{WARNING} or worse, so the info message is
  5.1276 +discarded.
  5.1277 +
  5.1278 +The timestamp is of the form
  5.1279 +``year-month-day hour:minutes:seconds,milliseconds.''
  5.1280 +Note that despite the three digits of precision in the milliseconds field,
  5.1281 +not all systems provide time with this much precision.
  5.1282 +
  5.1283 +\subsubsection{Logging to a rotating set of files}
  5.1284 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/python/logging/logging-0.4.9.2/logging/__init__.py	Thu Jul 22 13:42:39 2004 +0000
     6.3 @@ -0,0 +1,1225 @@
     6.4 +# Copyright 2001-2004 by Vinay Sajip. All Rights Reserved.
     6.5 +#
     6.6 +# Permission to use, copy, modify, and distribute this software and its
     6.7 +# documentation for any purpose and without fee is hereby granted,
     6.8 +# provided that the above copyright notice appear in all copies and that
     6.9 +# both that copyright notice and this permission notice appear in
    6.10 +# supporting documentation, and that the name of Vinay Sajip
    6.11 +# not be used in advertising or publicity pertaining to distribution
    6.12 +# of the software without specific, written prior permission.
    6.13 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    6.14 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
    6.15 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
    6.16 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
    6.17 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
    6.18 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    6.19 +
    6.20 +"""
    6.21 +Logging package for Python. Based on PEP 282 and comments thereto in
    6.22 +comp.lang.python, and influenced by Apache's log4j system.
    6.23 +
    6.24 +Should work under Python versions >= 1.5.2, except that source line
    6.25 +information is not available unless 'sys._getframe()' is.
    6.26 +
    6.27 +Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
    6.28 +
    6.29 +To use, simply 'import logging' and log away!
    6.30 +"""
    6.31 +
    6.32 +import sys, os, types, time, string, cStringIO
    6.33 +
    6.34 +try:
    6.35 +    import thread
    6.36 +    import threading
    6.37 +except ImportError:
    6.38 +    thread = None
    6.39 +
    6.40 +__author__  = "Vinay Sajip <vinay_sajip@red-dove.com>"
    6.41 +__status__  = "beta"
    6.42 +__version__ = "0.4.9.2"
    6.43 +__date__    = "28 February 2004"
    6.44 +
    6.45 +#---------------------------------------------------------------------------
    6.46 +#   Miscellaneous module data
    6.47 +#---------------------------------------------------------------------------
    6.48 +
    6.49 +#
    6.50 +#_srcfile is used when walking the stack to check when we've got the first
    6.51 +# caller stack frame.
    6.52 +#
    6.53 +if string.lower(__file__[-4:]) in ['.pyc', '.pyo']:
    6.54 +    _srcfile = __file__[:-4] + '.py'
    6.55 +else:
    6.56 +    _srcfile = __file__
    6.57 +_srcfile = os.path.normcase(_srcfile)
    6.58 +
    6.59 +# _srcfile is only used in conjunction with sys._getframe().
    6.60 +# To provide compatibility with older versions of Python, set _srcfile
    6.61 +# to None if _getframe() is not available; this value will prevent
    6.62 +# findCaller() from being called.
    6.63 +if not hasattr(sys, "_getframe"):
    6.64 +    _srcfile = None
    6.65 +
    6.66 +#
    6.67 +#_startTime is used as the base when calculating the relative time of events
    6.68 +#
    6.69 +_startTime = time.time()
    6.70 +
    6.71 +#
    6.72 +#raiseExceptions is used to see if exceptions during handling should be
    6.73 +#propagated
    6.74 +#
    6.75 +raiseExceptions = 1
    6.76 +
    6.77 +#---------------------------------------------------------------------------
    6.78 +#   Level related stuff
    6.79 +#---------------------------------------------------------------------------
    6.80 +#
    6.81 +# Default levels and level names, these can be replaced with any positive set
    6.82 +# of values having corresponding names. There is a pseudo-level, NOTSET, which
    6.83 +# is only really there as a lower limit for user-defined levels. Handlers and
    6.84 +# loggers are initialized with NOTSET so that they will log all messages, even
    6.85 +# at user-defined levels.
    6.86 +#
    6.87 +CRITICAL = 50
    6.88 +FATAL = CRITICAL
    6.89 +ERROR = 40
    6.90 +WARNING = 30
    6.91 +WARN = WARNING
    6.92 +INFO = 20
    6.93 +DEBUG = 10
    6.94 +NOTSET = 0
    6.95 +
    6.96 +_levelNames = {
    6.97 +    CRITICAL : 'CRITICAL',
    6.98 +    ERROR : 'ERROR',
    6.99 +    WARNING : 'WARNING',
   6.100 +    INFO : 'INFO',
   6.101 +    DEBUG : 'DEBUG',
   6.102 +    NOTSET : 'NOTSET',
   6.103 +    'CRITICAL' : CRITICAL,
   6.104 +    'ERROR' : ERROR,
   6.105 +    'WARN' : WARNING,
   6.106 +    'WARNING' : WARNING,
   6.107 +    'INFO' : INFO,
   6.108 +    'DEBUG' : DEBUG,
   6.109 +    'NOTSET' : NOTSET,
   6.110 +}
   6.111 +
   6.112 +def getLevelName(level):
   6.113 +    """
   6.114 +    Return the textual representation of logging level 'level'.
   6.115 +
   6.116 +    If the level is one of the predefined levels (CRITICAL, ERROR, WARNING,
   6.117 +    INFO, DEBUG) then you get the corresponding string. If you have
   6.118 +    associated levels with names using addLevelName then the name you have
   6.119 +    associated with 'level' is returned. Otherwise, the string
   6.120 +    "Level %s" % level is returned.
   6.121 +    """
   6.122 +    return _levelNames.get(level, ("Level %s" % level))
   6.123 +
   6.124 +def addLevelName(level, levelName):
   6.125 +    """
   6.126 +    Associate 'levelName' with 'level'.
   6.127 +
   6.128 +    This is used when converting levels to text during message formatting.
   6.129 +    """
   6.130 +    _acquireLock()
   6.131 +    try:    #unlikely to cause an exception, but you never know...
   6.132 +        _levelNames[level] = levelName
   6.133 +        _levelNames[levelName] = level
   6.134 +    finally:
   6.135 +        _releaseLock()
   6.136 +
   6.137 +#---------------------------------------------------------------------------
   6.138 +#   Thread-related stuff
   6.139 +#---------------------------------------------------------------------------
   6.140 +
   6.141 +#
   6.142 +#_lock is used to serialize access to shared data structures in this module.
   6.143 +#This needs to be an RLock because fileConfig() creates Handlers and so
   6.144 +#might arbitrary user threads. Since Handler.__init__() updates the shared
   6.145 +#dictionary _handlers, it needs to acquire the lock. But if configuring,
   6.146 +#the lock would already have been acquired - so we need an RLock.
   6.147 +#The same argument applies to Loggers and Manager.loggerDict.
   6.148 +#
   6.149 +_lock = None
   6.150 +
   6.151 +def _acquireLock():
   6.152 +    """
   6.153 +    Acquire the module-level lock for serializing access to shared data.
   6.154 +
   6.155 +    This should be released with _releaseLock().
   6.156 +    """
   6.157 +    global _lock
   6.158 +    if (not _lock) and thread:
   6.159 +        _lock = threading.RLock()
   6.160 +    if _lock:
   6.161 +        _lock.acquire()
   6.162 +
   6.163 +def _releaseLock():
   6.164 +    """
   6.165 +    Release the module-level lock acquired by calling _acquireLock().
   6.166 +    """
   6.167 +    if _lock:
   6.168 +        _lock.release()
   6.169 +
   6.170 +#---------------------------------------------------------------------------
   6.171 +#   The logging record
   6.172 +#---------------------------------------------------------------------------
   6.173 +
   6.174 +class LogRecord:
   6.175 +    """
   6.176 +    A LogRecord instance represents an event being logged.
   6.177 +
   6.178 +    LogRecord instances are created every time something is logged. They
   6.179 +    contain all the information pertinent to the event being logged. The
   6.180 +    main information passed in is in msg and args, which are combined
   6.181 +    using str(msg) % args to create the message field of the record. The
   6.182 +    record also includes information such as when the record was created,
   6.183 +    the source line where the logging call was made, and any exception
   6.184 +    information to be logged.
   6.185 +    """
   6.186 +    def __init__(self, name, level, pathname, lineno, msg, args, exc_info):
   6.187 +        """
   6.188 +        Initialize a logging record with interesting information.
   6.189 +        """
   6.190 +        ct = time.time()
   6.191 +        self.name = name
   6.192 +        self.msg = msg
   6.193 +        self.args = args
   6.194 +        self.levelname = getLevelName(level)
   6.195 +        self.levelno = level
   6.196 +        self.pathname = pathname
   6.197 +        try:
   6.198 +            self.filename = os.path.basename(pathname)
   6.199 +            self.module = os.path.splitext(self.filename)[0]
   6.200 +        except:
   6.201 +            self.filename = pathname
   6.202 +            self.module = "Unknown module"
   6.203 +        self.exc_info = exc_info
   6.204 +        self.exc_text = None      # used to cache the traceback text
   6.205 +        self.lineno = lineno
   6.206 +        self.created = ct
   6.207 +        self.msecs = (ct - long(ct)) * 1000
   6.208 +        self.relativeCreated = (self.created - _startTime) * 1000
   6.209 +        if thread:
   6.210 +            self.thread = thread.get_ident()
   6.211 +        else:
   6.212 +            self.thread = None
   6.213 +        if hasattr(os, 'getpid'):
   6.214 +            self.process = os.getpid()
   6.215 +        else:
   6.216 +            self.process = None
   6.217 +
   6.218 +    def __str__(self):
   6.219 +        return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno,
   6.220 +            self.pathname, self.lineno, self.msg)
   6.221 +
   6.222 +    def getMessage(self):
   6.223 +        """
   6.224 +        Return the message for this LogRecord.
   6.225 +
   6.226 +        Return the message for this LogRecord after merging any user-supplied
   6.227 +        arguments with the message.
   6.228 +        """
   6.229 +        if not hasattr(types, "UnicodeType"): #if no unicode support...
   6.230 +            msg = str(self.msg)
   6.231 +        else:
   6.232 +            try:
   6.233 +                msg = str(self.msg)
   6.234 +            except UnicodeError:
   6.235 +                msg = self.msg      #Defer encoding till later
   6.236 +        if self.args:
   6.237 +            msg = msg % self.args
   6.238 +        return msg
   6.239 +
   6.240 +def makeLogRecord(dict):
   6.241 +    """
   6.242 +    Make a LogRecord whose attributes are defined by the specified dictionary,
   6.243 +    This function is useful for converting a logging event received over
   6.244 +    a socket connection (which is sent as a dictionary) into a LogRecord
   6.245 +    instance.
   6.246 +    """
   6.247 +    rv = LogRecord(None, None, "", 0, "", (), None)
   6.248 +    rv.__dict__.update(dict)
   6.249 +    return rv
   6.250 +
   6.251 +#---------------------------------------------------------------------------
   6.252 +#   Formatter classes and functions
   6.253 +#---------------------------------------------------------------------------
   6.254 +
   6.255 +class Formatter:
   6.256 +    """
   6.257 +    Formatter instances are used to convert a LogRecord to text.
   6.258 +
   6.259 +    Formatters need to know how a LogRecord is constructed. They are
   6.260 +    responsible for converting a LogRecord to (usually) a string which can
   6.261 +    be interpreted by either a human or an external system. The base Formatter
   6.262 +    allows a formatting string to be specified. If none is supplied, the
   6.263 +    default value of "%s(message)\\n" is used.
   6.264 +
   6.265 +    The Formatter can be initialized with a format string which makes use of
   6.266 +    knowledge of the LogRecord attributes - e.g. the default value mentioned
   6.267 +    above makes use of the fact that the user's message and arguments are pre-
   6.268 +    formatted into a LogRecord's message attribute. Currently, the useful
   6.269 +    attributes in a LogRecord are described by:
   6.270 +
   6.271 +    %(name)s            Name of the logger (logging channel)
   6.272 +    %(levelno)s         Numeric logging level for the message (DEBUG, INFO,
   6.273 +                        WARNING, ERROR, CRITICAL)
   6.274 +    %(levelname)s       Text logging level for the message ("DEBUG", "INFO",
   6.275 +                        "WARNING", "ERROR", "CRITICAL")
   6.276 +    %(pathname)s        Full pathname of the source file where the logging
   6.277 +                        call was issued (if available)
   6.278 +    %(filename)s        Filename portion of pathname
   6.279 +    %(module)s          Module (name portion of filename)
   6.280 +    %(lineno)d          Source line number where the logging call was issued
   6.281 +                        (if available)
   6.282 +    %(created)f         Time when the LogRecord was created (time.time()
   6.283 +                        return value)
   6.284 +    %(asctime)s         Textual time when the LogRecord was created
   6.285 +    %(msecs)d           Millisecond portion of the creation time
   6.286 +    %(relativeCreated)d Time in milliseconds when the LogRecord was created,
   6.287 +                        relative to the time the logging module was loaded
   6.288 +                        (typically at application startup time)
   6.289 +    %(thread)d          Thread ID (if available)
   6.290 +    %(process)d         Process ID (if available)
   6.291 +    %(message)s         The result of record.getMessage(), computed just as
   6.292 +                        the record is emitted
   6.293 +    """
   6.294 +
   6.295 +    converter = time.localtime
   6.296 +
   6.297 +    def __init__(self, fmt=None, datefmt=None):
   6.298 +        """
   6.299 +        Initialize the formatter with specified format strings.
   6.300 +
   6.301 +        Initialize the formatter either with the specified format string, or a
   6.302 +        default as described above. Allow for specialized date formatting with
   6.303 +        the optional datefmt argument (if omitted, you get the ISO8601 format).
   6.304 +        """
   6.305 +        if fmt:
   6.306 +            self._fmt = fmt
   6.307 +        else:
   6.308 +            self._fmt = "%(message)s"
   6.309 +        self.datefmt = datefmt
   6.310 +
   6.311 +    def formatTime(self, record, datefmt=None):
   6.312 +        """
   6.313 +        Return the creation time of the specified LogRecord as formatted text.
   6.314 +
   6.315 +        This method should be called from format() by a formatter which
   6.316 +        wants to make use of a formatted time. This method can be overridden
   6.317 +        in formatters to provide for any specific requirement, but the
   6.318 +        basic behaviour is as follows: if datefmt (a string) is specified,
   6.319 +        it is used with time.strftime() to format the creation time of the
   6.320 +        record. Otherwise, the ISO8601 format is used. The resulting
   6.321 +        string is returned. This function uses a user-configurable function
   6.322 +        to convert the creation time to a tuple. By default, time.localtime()
   6.323 +        is used; to change this for a particular formatter instance, set the
   6.324 +        'converter' attribute to a function with the same signature as
   6.325 +        time.localtime() or time.gmtime(). To change it for all formatters,
   6.326 +        for example if you want all logging times to be shown in GMT,
   6.327 +        set the 'converter' attribute in the Formatter class.
   6.328 +        """
   6.329 +        ct = self.converter(record.created)
   6.330 +        if datefmt:
   6.331 +            s = time.strftime(datefmt, ct)
   6.332 +        else:
   6.333 +            t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
   6.334 +            s = "%s,%03d" % (t, record.msecs)
   6.335 +        return s
   6.336 +
   6.337 +    def formatException(self, ei):
   6.338 +        """
   6.339 +        Format and return the specified exception information as a string.
   6.340 +
   6.341 +        This default implementation just uses
   6.342 +        traceback.print_exception()
   6.343 +        """
   6.344 +        import traceback
   6.345 +        sio = cStringIO.StringIO()
   6.346 +        traceback.print_exception(ei[0], ei[1], ei[2], None, sio)
   6.347 +        s = sio.getvalue()
   6.348 +        sio.close()
   6.349 +        if s[-1] == "\n":
   6.350 +            s = s[:-1]
   6.351 +        return s
   6.352 +
   6.353 +    def format(self, record):
   6.354 +        """
   6.355 +        Format the specified record as text.
   6.356 +
   6.357 +        The record's attribute dictionary is used as the operand to a
   6.358 +        string formatting operation which yields the returned string.
   6.359 +        Before formatting the dictionary, a couple of preparatory steps
   6.360 +        are carried out. The message attribute of the record is computed
   6.361 +        using LogRecord.getMessage(). If the formatting string contains
   6.362 +        "%(asctime)", formatTime() is called to format the event time.
   6.363 +        If there is exception information, it is formatted using
   6.364 +        formatException() and appended to the message.
   6.365 +        """
   6.366 +        record.message = record.getMessage()
   6.367 +        if string.find(self._fmt,"%(asctime)") >= 0:
   6.368 +            record.asctime = self.formatTime(record, self.datefmt)
   6.369 +        s = self._fmt % record.__dict__
   6.370 +        if record.exc_info:
   6.371 +            # Cache the traceback text to avoid converting it multiple times
   6.372 +            # (it's constant anyway)
   6.373 +            if not record.exc_text:
   6.374 +                record.exc_text = self.formatException(record.exc_info)
   6.375 +        if record.exc_text:
   6.376 +            if s[-1] != "\n":
   6.377 +                s = s + "\n"
   6.378 +            s = s + record.exc_text
   6.379 +        return s
   6.380 +
   6.381 +#
   6.382 +#   The default formatter to use when no other is specified
   6.383 +#
   6.384 +_defaultFormatter = Formatter()
   6.385 +
   6.386 +class BufferingFormatter:
   6.387 +    """
   6.388 +    A formatter suitable for formatting a number of records.
   6.389 +    """
   6.390 +    def __init__(self, linefmt=None):
   6.391 +        """
   6.392 +        Optionally specify a formatter which will be used to format each
   6.393 +        individual record.
   6.394 +        """
   6.395 +        if linefmt:
   6.396 +            self.linefmt = linefmt
   6.397 +        else:
   6.398 +            self.linefmt = _defaultFormatter
   6.399 +
   6.400 +    def formatHeader(self, records):
   6.401 +        """
   6.402 +        Return the header string for the specified records.
   6.403 +        """
   6.404 +        return ""
   6.405 +
   6.406 +    def formatFooter(self, records):
   6.407 +        """
   6.408 +        Return the footer string for the specified records.
   6.409 +        """
   6.410 +        return ""
   6.411 +
   6.412 +    def format(self, records):
   6.413 +        """
   6.414 +        Format the specified records and return the result as a string.
   6.415 +        """
   6.416 +        rv = ""
   6.417 +        if len(records) > 0:
   6.418 +            rv = rv + self.formatHeader(records)
   6.419 +            for record in records:
   6.420 +                rv = rv + self.linefmt.format(record)
   6.421 +            rv = rv + self.formatFooter(records)
   6.422 +        return rv
   6.423 +
   6.424 +#---------------------------------------------------------------------------
   6.425 +#   Filter classes and functions
   6.426 +#---------------------------------------------------------------------------
   6.427 +
   6.428 +class Filter:
   6.429 +    """
   6.430 +    Filter instances are used to perform arbitrary filtering of LogRecords.
   6.431 +
   6.432 +    Loggers and Handlers can optionally use Filter instances to filter
   6.433 +    records as desired. The base filter class only allows events which are
   6.434 +    below a certain point in the logger hierarchy. For example, a filter
   6.435 +    initialized with "A.B" will allow events logged by loggers "A.B",
   6.436 +    "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If
   6.437 +    initialized with the empty string, all events are passed.
   6.438 +    """
   6.439 +    def __init__(self, name=''):
   6.440 +        """
   6.441 +        Initialize a filter.
   6.442 +
   6.443 +        Initialize with the name of the logger which, together with its
   6.444 +        children, will have its events allowed through the filter. If no
   6.445 +        name is specified, allow every event.
   6.446 +        """
   6.447 +        self.name = name
   6.448 +        self.nlen = len(name)
   6.449 +
   6.450 +    def filter(self, record):
   6.451 +        """
   6.452 +        Determine if the specified record is to be logged.
   6.453 +
   6.454 +        Is the specified record to be logged? Returns 0 for no, nonzero for
   6.455 +        yes. If deemed appropriate, the record may be modified in-place.
   6.456 +        """
   6.457 +        if self.nlen == 0:
   6.458 +            return 1
   6.459 +        elif self.name == record.name:
   6.460 +            return 1
   6.461 +        elif string.find(record.name, self.name, 0, self.nlen) != 0:
   6.462 +            return 0
   6.463 +        return (record.name[self.nlen] == ".")
   6.464 +
   6.465 +class Filterer:
   6.466 +    """
   6.467 +    A base class for loggers and handlers which allows them to share
   6.468 +    common code.
   6.469 +    """
   6.470 +    def __init__(self):
   6.471 +        """
   6.472 +        Initialize the list of filters to be an empty list.
   6.473 +        """
   6.474 +        self.filters = []
   6.475 +
   6.476 +    def addFilter(self, filter):
   6.477 +        """
   6.478 +        Add the specified filter to this handler.
   6.479 +        """
   6.480 +        if not (filter in self.filters):
   6.481 +            self.filters.append(filter)
   6.482 +
   6.483 +    def removeFilter(self, filter):
   6.484 +        """
   6.485 +        Remove the specified filter from this handler.
   6.486 +        """
   6.487 +        if filter in self.filters:
   6.488 +            self.filters.remove(filter)
   6.489 +
   6.490 +    def filter(self, record):
   6.491 +        """
   6.492 +        Determine if a record is loggable by consulting all the filters.
   6.493 +
   6.494 +        The default is to allow the record to be logged; any filter can veto
   6.495 +        this and the record is then dropped. Returns a zero value if a record
   6.496 +        is to be dropped, else non-zero.
   6.497 +        """
   6.498 +        rv = 1
   6.499 +        for f in self.filters:
   6.500 +            if not f.filter(record):
   6.501 +                rv = 0
   6.502 +                break
   6.503 +        return rv
   6.504 +
   6.505 +#---------------------------------------------------------------------------
   6.506 +#   Handler classes and functions
   6.507 +#---------------------------------------------------------------------------
   6.508 +
   6.509 +_handlers = {}  #repository of handlers (for flushing when shutdown called)
   6.510 +
   6.511 +class Handler(Filterer):
   6.512 +    """
   6.513 +    Handler instances dispatch logging events to specific destinations.
   6.514 +
   6.515 +    The base handler class. Acts as a placeholder which defines the Handler
   6.516 +    interface. Handlers can optionally use Formatter instances to format
   6.517 +    records as desired. By default, no formatter is specified; in this case,
   6.518 +    the 'raw' message as determined by record.message is logged.
   6.519 +    """
   6.520 +    def __init__(self, level=NOTSET):
   6.521 +        """
   6.522 +        Initializes the instance - basically setting the formatter to None
   6.523 +        and the filter list to empty.
   6.524 +        """
   6.525 +        Filterer.__init__(self)
   6.526 +        self.level = level
   6.527 +        self.formatter = None
   6.528 +        #get the module data lock, as we're updating a shared structure.
   6.529 +        _acquireLock()
   6.530 +        try:    #unlikely to raise an exception, but you never know...
   6.531 +            _handlers[self] = 1
   6.532 +        finally:
   6.533 +            _releaseLock()
   6.534 +        self.createLock()
   6.535 +
   6.536 +    def createLock(self):
   6.537 +        """
   6.538 +        Acquire a thread lock for serializing access to the underlying I/O.
   6.539 +        """
   6.540 +        if thread:
   6.541 +            self.lock = thread.allocate_lock()
   6.542 +        else:
   6.543 +            self.lock = None
   6.544 +
   6.545 +    def acquire(self):
   6.546 +        """
   6.547 +        Acquire the I/O thread lock.
   6.548 +        """
   6.549 +        if self.lock:
   6.550 +            self.lock.acquire()
   6.551 +
   6.552 +    def release(self):
   6.553 +        """
   6.554 +        Release the I/O thread lock.
   6.555 +        """
   6.556 +        if self.lock:
   6.557 +            self.lock.release()
   6.558 +
   6.559 +    def setLevel(self, level):
   6.560 +        """
   6.561 +        Set the logging level of this handler.
   6.562 +        """
   6.563 +        self.level = level
   6.564 +
   6.565 +    def format(self, record):
   6.566 +        """
   6.567 +        Format the specified record.
   6.568 +
   6.569 +        If a formatter is set, use it. Otherwise, use the default formatter
   6.570 +        for the module.
   6.571 +        """
   6.572 +        if self.formatter:
   6.573 +            fmt = self.formatter
   6.574 +        else:
   6.575 +            fmt = _defaultFormatter
   6.576 +        return fmt.format(record)
   6.577 +
   6.578 +    def emit(self, record):
   6.579 +        """
   6.580 +        Do whatever it takes to actually log the specified logging record.
   6.581 +
   6.582 +        This version is intended to be implemented by subclasses and so
   6.583 +        raises a NotImplementedError.
   6.584 +        """
   6.585 +        raise NotImplementedError, 'emit must be implemented '\
   6.586 +                                    'by Handler subclasses'
   6.587 +
   6.588 +    def handle(self, record):
   6.589 +        """
   6.590 +        Conditionally emit the specified logging record.
   6.591 +
   6.592 +        Emission depends on filters which may have been added to the handler.
   6.593 +        Wrap the actual emission of the record with acquisition/release of
   6.594 +        the I/O thread lock. Returns whether the filter passed the record for
   6.595 +        emission.
   6.596 +        """
   6.597 +        rv = self.filter(record)
   6.598 +        if rv:
   6.599 +            self.acquire()
   6.600 +            try:
   6.601 +                self.emit(record)
   6.602 +            finally:
   6.603 +                self.release()
   6.604 +        return rv
   6.605 +
   6.606 +    def setFormatter(self, fmt):
   6.607 +        """
   6.608 +        Set the formatter for this handler.
   6.609 +        """
   6.610 +        self.formatter = fmt
   6.611 +
   6.612 +    def flush(self):
   6.613 +        """
   6.614 +        Ensure all logging output has been flushed.
   6.615 +
   6.616 +        This version does nothing and is intended to be implemented by
   6.617 +        subclasses.
   6.618 +        """
   6.619 +        pass
   6.620 +
   6.621 +    def close(self):
   6.622 +        """
   6.623 +        Tidy up any resources used by the handler.
   6.624 +
   6.625 +        This version does removes the handler from an internal list
   6.626 +        of handlers which is closed when shutdown() is called. Subclasses
   6.627 +        should ensure that this gets called from overridden close()
   6.628 +        methods.
   6.629 +        """
   6.630 +        #get the module data lock, as we're updating a shared structure.
   6.631 +        _acquireLock()
   6.632 +        try:    #unlikely to raise an exception, but you never know...
   6.633 +            del _handlers[self]
   6.634 +        finally:
   6.635 +            _releaseLock()
   6.636 +
   6.637 +    def handleError(self, record):
   6.638 +        """
   6.639 +        Handle errors which occur during an emit() call.
   6.640 +
   6.641 +        This method should be called from handlers when an exception is
   6.642 +        encountered during an emit() call. If raiseExceptions is false,
   6.643 +        exceptions get silently ignored. This is what is mostly wanted
   6.644 +        for a logging system - most users will not care about errors in
   6.645 +        the logging system, they are more interested in application errors.
   6.646 +        You could, however, replace this with a custom handler if you wish.
   6.647 +        The record which was being processed is passed in to this method.
   6.648 +        """
   6.649 +        if raiseExceptions:
   6.650 +            import traceback
   6.651 +            ei = sys.exc_info()
   6.652 +            traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
   6.653 +            del ei
   6.654 +
   6.655 +class StreamHandler(Handler):
   6.656 +    """
   6.657 +    A handler class which writes logging records, appropriately formatted,
   6.658 +    to a stream. Note that this class does not close the stream, as
   6.659 +    sys.stdout or sys.stderr may be used.
   6.660 +    """
   6.661 +    def __init__(self, strm=None):
   6.662 +        """
   6.663 +        Initialize the handler.
   6.664 +
   6.665 +        If strm is not specified, sys.stderr is used.
   6.666 +        """
   6.667 +        Handler.__init__(self)
   6.668 +        if not strm:
   6.669 +            strm = sys.stderr
   6.670 +        self.stream = strm
   6.671 +        self.formatter = None
   6.672 +
   6.673 +    def flush(self):
   6.674 +        """
   6.675 +        Flushes the stream.
   6.676 +        """
   6.677 +        self.stream.flush()
   6.678 +
   6.679 +    def emit(self, record):
   6.680 +        """
   6.681 +        Emit a record.
   6.682 +
   6.683 +        If a formatter is specified, it is used to format the record.
   6.684 +        The record is then written to the stream with a trailing newline
   6.685 +        [N.B. this may be removed depending on feedback]. If exception
   6.686 +        information is present, it is formatted using
   6.687 +        traceback.print_exception and appended to the stream.
   6.688 +        """
   6.689 +        try:
   6.690 +            msg = self.format(record)
   6.691 +            if not hasattr(types, "UnicodeType"): #if no unicode support...
   6.692 +                self.stream.write("%s\n" % msg)
   6.693 +            else:
   6.694 +                try:
   6.695 +                    self.stream.write("%s\n" % msg)
   6.696 +                except UnicodeError:
   6.697 +                    self.stream.write("%s\n" % msg.encode("UTF-8"))
   6.698 +            self.flush()
   6.699 +        except:
   6.700 +            self.handleError(record)
   6.701 +
   6.702 +class FileHandler(StreamHandler):
   6.703 +    """
   6.704 +    A handler class which writes formatted logging records to disk files.
   6.705 +    """
   6.706 +    def __init__(self, filename, mode="a"):
   6.707 +        """
   6.708 +        Open the specified file and use it as the stream for logging.
   6.709 +        """
   6.710 +        StreamHandler.__init__(self, open(filename, mode))
   6.711 +        self.baseFilename = filename
   6.712 +        self.mode = mode
   6.713 +
   6.714 +    def close(self):
   6.715 +        """
   6.716 +        Closes the stream.
   6.717 +        """
   6.718 +        self.flush()
   6.719 +        self.stream.close()
   6.720 +        StreamHandler.close(self)
   6.721 +
   6.722 +#---------------------------------------------------------------------------
   6.723 +#   Manager classes and functions
   6.724 +#---------------------------------------------------------------------------
   6.725 +
   6.726 +class PlaceHolder:
   6.727 +    """
   6.728 +    PlaceHolder instances are used in the Manager logger hierarchy to take
   6.729 +    the place of nodes for which no loggers have been defined. This class is
   6.730 +    intended for internal use only and not as part of the public API.
   6.731 +    """
   6.732 +    def __init__(self, alogger):
   6.733 +        """
   6.734 +        Initialize with the specified logger being a child of this placeholder.
   6.735 +        """
   6.736 +        self.loggers = [alogger]
   6.737 +
   6.738 +    def append(self, alogger):
   6.739 +        """
   6.740 +        Add the specified logger as a child of this placeholder.
   6.741 +        """
   6.742 +        if alogger not in self.loggers:
   6.743 +            self.loggers.append(alogger)
   6.744 +
   6.745 +#
   6.746 +#   Determine which class to use when instantiating loggers.
   6.747 +#
   6.748 +_loggerClass = None
   6.749 +
   6.750 +def setLoggerClass(klass):
   6.751 +    """
   6.752 +    Set the class to be used when instantiating a logger. The class should
   6.753 +    define __init__() such that only a name argument is required, and the
   6.754 +    __init__() should call Logger.__init__()
   6.755 +    """
   6.756 +    if klass != Logger:
   6.757 +        if not issubclass(klass, Logger):
   6.758 +            raise TypeError, "logger not derived from logging.Logger: " + \
   6.759 +                            klass.__name__
   6.760 +    global _loggerClass
   6.761 +    _loggerClass = klass
   6.762 +
   6.763 +class Manager:
   6.764 +    """
   6.765 +    There is [under normal circumstances] just one Manager instance, which
   6.766 +    holds the hierarchy of loggers.
   6.767 +    """
   6.768 +    def __init__(self, rootnode):
   6.769 +        """
   6.770 +        Initialize the manager with the root node of the logger hierarchy.
   6.771 +        """
   6.772 +        self.root = rootnode
   6.773 +        self.disable = 0
   6.774 +        self.emittedNoHandlerWarning = 0
   6.775 +        self.loggerDict = {}
   6.776 +
   6.777 +    def getLogger(self, name):
   6.778 +        """
   6.779 +        Get a logger with the specified name (channel name), creating it
   6.780 +        if it doesn't yet exist.
   6.781 +
   6.782 +        If a PlaceHolder existed for the specified name [i.e. the logger
   6.783 +        didn't exist but a child of it did], replace it with the created
   6.784 +        logger and fix up the parent/child references which pointed to the
   6.785 +        placeholder to now point to the logger.
   6.786 +        """
   6.787 +        rv = None
   6.788 +        _acquireLock()
   6.789 +        try:
   6.790 +            if self.loggerDict.has_key(name):
   6.791 +                rv = self.loggerDict[name]
   6.792 +                if isinstance(rv, PlaceHolder):
   6.793 +                    ph = rv
   6.794 +                    rv = _loggerClass(name)
   6.795 +                    rv.manager = self
   6.796 +                    self.loggerDict[name] = rv
   6.797 +                    self._fixupChildren(ph, rv)
   6.798 +                    self._fixupParents(rv)
   6.799 +            else:
   6.800 +                rv = _loggerClass(name)
   6.801 +                rv.manager = self
   6.802 +                self.loggerDict[name] = rv
   6.803 +                self._fixupParents(rv)
   6.804 +        finally:
   6.805 +            _releaseLock()
   6.806 +        return rv
   6.807 +
   6.808 +    def _fixupParents(self, alogger):
   6.809 +        """
   6.810 +        Ensure that there are either loggers or placeholders all the way
   6.811 +        from the specified logger to the root of the logger hierarchy.
   6.812 +        """
   6.813 +        name = alogger.name
   6.814 +        i = string.rfind(name, ".")
   6.815 +        rv = None
   6.816 +        while (i > 0) and not rv:
   6.817 +            substr = name[:i]
   6.818 +            if not self.loggerDict.has_key(substr):
   6.819 +                self.loggerDict[substr] = PlaceHolder(alogger)
   6.820 +            else:
   6.821 +                obj = self.loggerDict[substr]
   6.822 +                if isinstance(obj, Logger):
   6.823 +                    rv = obj
   6.824 +                else:
   6.825 +                    assert isinstance(obj, PlaceHolder)
   6.826 +                    obj.append(alogger)
   6.827 +            i = string.rfind(name, ".", 0, i - 1)
   6.828 +        if not rv:
   6.829 +            rv = self.root
   6.830 +        alogger.parent = rv
   6.831 +
   6.832 +    def _fixupChildren(self, ph, alogger):
   6.833 +        """
   6.834 +        Ensure that children of the placeholder ph are connected to the
   6.835 +        specified logger.
   6.836 +        """
   6.837 +        for c in ph.loggers:
   6.838 +            if string.find(c.parent.name, alogger.name) <> 0:
   6.839 +                alogger.parent = c.parent
   6.840 +                c.parent = alogger
   6.841 +
   6.842 +#---------------------------------------------------------------------------
   6.843 +#   Logger classes and functions
   6.844 +#---------------------------------------------------------------------------
   6.845 +
   6.846 +class Logger(Filterer):
   6.847 +    """
   6.848 +    Instances of the Logger class represent a single logging channel. A
   6.849 +    "logging channel" indicates an area of an application. Exactly how an
   6.850 +    "area" is defined is up to the application developer. Since an
   6.851 +    application can have any number of areas, logging channels are identified
   6.852 +    by a unique string. Application areas can be nested (e.g. an area
   6.853 +    of "input processing" might include sub-areas "read CSV files", "read
   6.854 +    XLS files" and "read Gnumeric files"). To cater for this natural nesting,
   6.855 +    channel names are organized into a namespace hierarchy where levels are
   6.856 +    separated by periods, much like the Java or Python package namespace. So
   6.857 +    in the instance given above, channel names might be "input" for the upper
   6.858 +    level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels.
   6.859 +    There is no arbitrary limit to the depth of nesting.
   6.860 +    """
   6.861 +    def __init__(self, name, level=NOTSET):
   6.862 +        """
   6.863 +        Initialize the logger with a name and an optional level.
   6.864 +        """
   6.865 +        Filterer.__init__(self)
   6.866 +        self.name = name
   6.867 +        self.level = level
   6.868 +        self.parent = None
   6.869 +        self.propagate = 1
   6.870 +        self.handlers = []
   6.871 +        self.disabled = 0
   6.872 +
   6.873 +    def setLevel(self, level):
   6.874 +        """
   6.875 +        Set the logging level of this logger.
   6.876 +        """
   6.877 +        self.level = level
   6.878 +
   6.879 +#   def getRoot(self):
   6.880 +#       """
   6.881 +#       Get the root of the logger hierarchy.
   6.882 +#       """
   6.883 +#       return Logger.root
   6.884 +
   6.885 +    def debug(self, msg, *args, **kwargs):
   6.886 +        """
   6.887 +        Log 'msg % args' with severity 'DEBUG'.
   6.888 +
   6.889 +        To pass exception information, use the keyword argument exc_info with
   6.890 +        a true value, e.g.
   6.891 +
   6.892 +        logger.debug("Houston, we have a %s", "thorny problem", exc_info=1)
   6.893 +        """
   6.894 +        if self.manager.disable >= DEBUG:
   6.895 +            return
   6.896 +        if DEBUG >= self.getEffectiveLevel():
   6.897 +            apply(self._log, (DEBUG, msg, args), kwargs)
   6.898 +
   6.899 +    def info(self, msg, *args, **kwargs):
   6.900 +        """
   6.901 +        Log 'msg % args' with severity 'INFO'.
   6.902 +
   6.903 +        To pass exception information, use the keyword argument exc_info with
   6.904 +        a true value, e.g.
   6.905 +
   6.906 +        logger.info("Houston, we have a %s", "interesting problem", exc_info=1)
   6.907 +        """
   6.908 +        if self.manager.disable >= INFO:
   6.909 +            return
   6.910 +        if INFO >= self.getEffectiveLevel():
   6.911 +            apply(self._log, (INFO, msg, args), kwargs)
   6.912 +
   6.913 +    def warning(self, msg, *args, **kwargs):
   6.914 +        """
   6.915 +        Log 'msg % args' with severity 'WARNING'.
   6.916 +
   6.917 +        To pass exception information, use the keyword argument exc_info with
   6.918 +        a true value, e.g.
   6.919 +
   6.920 +        logger.warning("Houston, we have a %s", "bit of a problem", exc_info=1)
   6.921 +        """
   6.922 +        if self.manager.disable >= WARNING:
   6.923 +            return
   6.924 +        if self.isEnabledFor(WARNING):
   6.925 +            apply(self._log, (WARNING, msg, args), kwargs)
   6.926 +
   6.927 +    warn = warning
   6.928 +
   6.929 +    def error(self, msg, *args, **kwargs):
   6.930 +        """
   6.931 +        Log 'msg % args' with severity 'ERROR'.
   6.932 +
   6.933 +        To pass exception information, use the keyword argument exc_info with
   6.934 +        a true value, e.g.
   6.935 +
   6.936 +        logger.error("Houston, we have a %s", "major problem", exc_info=1)
   6.937 +        """
   6.938 +        if self.manager.disable >= ERROR:
   6.939 +            return
   6.940 +        if self.isEnabledFor(ERROR):
   6.941 +            apply(self._log, (ERROR, msg, args), kwargs)
   6.942 +
   6.943 +    def exception(self, msg, *args):
   6.944 +        """
   6.945 +        Convenience method for logging an ERROR with exception information.
   6.946 +        """
   6.947 +        apply(self.error, (msg,) + args, {'exc_info': 1})
   6.948 +
   6.949 +    def critical(self, msg, *args, **kwargs):
   6.950 +        """
   6.951 +        Log 'msg % args' with severity 'CRITICAL'.
   6.952 +
   6.953 +        To pass exception information, use the keyword argument exc_info with
   6.954 +        a true value, e.g.
   6.955 +
   6.956 +        logger.critical("Houston, we have a %s", "major disaster", exc_info=1)
   6.957 +        """
   6.958 +        if self.manager.disable >= CRITICAL:
   6.959 +            return
   6.960 +        if CRITICAL >= self.getEffectiveLevel():
   6.961 +            apply(self._log, (CRITICAL, msg, args), kwargs)
   6.962 +
   6.963 +    fatal = critical
   6.964 +
   6.965 +    def log(self, level, msg, *args, **kwargs):
   6.966 +        """
   6.967 +        Log 'msg % args' with the severity 'level'.
   6.968 +
   6.969 +        To pass exception information, use the keyword argument exc_info with
   6.970 +        a true value, e.g.
   6.971 +
   6.972 +        logger.log(level, "We have a %s", "mysterious problem", exc_info=1)
   6.973 +        """
   6.974 +        if self.manager.disable >= level:
   6.975 +            return
   6.976 +        if self.isEnabledFor(level):
   6.977 +            apply(self._log, (level, msg, args), kwargs)
   6.978 +
   6.979 +    def findCaller(self):
   6.980 +        """
   6.981 +        Find the stack frame of the caller so that we can note the source
   6.982 +        file name and line number.
   6.983 +        """
   6.984 +        f = sys._getframe(1)
   6.985 +        while 1:
   6.986 +            co = f.f_code
   6.987 +            filename = os.path.normcase(co.co_filename)
   6.988 +            if filename == _srcfile:
   6.989 +                f = f.f_back
   6.990 +                continue
   6.991 +            return filename, f.f_lineno
   6.992 +
   6.993 +    def makeRecord(self, name, level, fn, lno, msg, args, exc_info):
   6.994 +        """
   6.995 +        A factory method which can be overridden in subclasses to create
   6.996 +        specialized LogRecords.
   6.997 +        """
   6.998 +        return LogRecord(name, level, fn, lno, msg, args, exc_info)
   6.999 +
  6.1000 +    def _log(self, level, msg, args, exc_info=None):
  6.1001 +        """
  6.1002 +        Low-level logging routine which creates a LogRecord and then calls
  6.1003 +        all the handlers of this logger to handle the record.
  6.1004 +        """
  6.1005 +        if _srcfile:
  6.1006 +            fn, lno = self.findCaller()
  6.1007 +        else:
  6.1008 +            fn, lno = "<unknown file>", 0
  6.1009 +        if exc_info:
  6.1010 +            if type(exc_info) != types.TupleType:
  6.1011 +                exc_info = sys.exc_info()
  6.1012 +        record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info)
  6.1013 +        self.handle(record)
  6.1014 +
  6.1015 +    def handle(self, record):
  6.1016 +        """
  6.1017 +        Call the handlers for the specified record.
  6.1018 +
  6.1019 +        This method is used for unpickled records received from a socket, as
  6.1020 +        well as those created locally. Logger-level filtering is applied.
  6.1021 +        """
  6.1022 +        if (not self.disabled) and self.filter(record):
  6.1023 +            self.callHandlers(record)
  6.1024 +
  6.1025 +    def addHandler(self, hdlr):
  6.1026 +        """
  6.1027 +        Add the specified handler to this logger.
  6.1028 +        """
  6.1029 +        if not (hdlr in self.handlers):
  6.1030 +            self.handlers.append(hdlr)
  6.1031 +
  6.1032 +    def removeHandler(self, hdlr):
  6.1033 +        """
  6.1034 +        Remove the specified handler from this logger.
  6.1035 +        """
  6.1036 +        if hdlr in self.handlers:
  6.1037 +            #hdlr.close()
  6.1038 +            self.handlers.remove(hdlr)
  6.1039 +
  6.1040 +    def callHandlers(self, record):
  6.1041 +        """
  6.1042 +        Pass a record to all relevant handlers.
  6.1043 +
  6.1044 +        Loop through all handlers for this logger and its parents in the
  6.1045 +        logger hierarchy. If no handler was found, output a one-off error
  6.1046 +        message to sys.stderr. Stop searching up the hierarchy whenever a
  6.1047 +        logger with the "propagate" attribute set to zero is found - that
  6.1048 +        will be the last logger whose handlers are called.
  6.1049 +        """
  6.1050 +        c = self
  6.1051 +        found = 0
  6.1052 +        while c:
  6.1053 +            for hdlr in c.handlers:
  6.1054 +                found = found + 1
  6.1055 +                if record.levelno >= hdlr.level:
  6.1056 +                    hdlr.handle(record)
  6.1057 +            if not c.propagate:
  6.1058 +                c = None    #break out
  6.1059 +            else:
  6.1060 +                c = c.parent
  6.1061 +        if (found == 0) and not self.manager.emittedNoHandlerWarning:
  6.1062 +            sys.stderr.write("No handlers could be found for logger"
  6.1063 +                             " \"%s\"\n" % self.name)
  6.1064 +            self.manager.emittedNoHandlerWarning = 1
  6.1065 +
  6.1066 +    def getEffectiveLevel(self):
  6.1067 +        """
  6.1068 +        Get the effective level for this logger.
  6.1069 +
  6.1070 +        Loop through this logger and its parents in the logger hierarchy,
  6.1071 +        looking for a non-zero logging level. Return the first one found.
  6.1072 +        """
  6.1073 +        logger = self
  6.1074 +        while logger:
  6.1075 +            if logger.level:
  6.1076 +                return logger.level
  6.1077 +            logger = logger.parent
  6.1078 +        return NOTSET
  6.1079 +
  6.1080 +    def isEnabledFor(self, level):
  6.1081 +        """
  6.1082 +        Is this logger enabled for level 'level'?
  6.1083 +        """
  6.1084 +        if self.manager.disable >= level:
  6.1085 +            return 0
  6.1086 +        return level >= self.getEffectiveLevel()
  6.1087 +
  6.1088 +class RootLogger(Logger):
  6.1089 +    """
  6.1090 +    A root logger is not that different to any other logger, except that
  6.1091 +    it must have a logging level and there is only one instance of it in
  6.1092 +    the hierarchy.
  6.1093 +    """
  6.1094 +    def __init__(self, level):
  6.1095 +        """
  6.1096 +        Initialize the logger with the name "root".
  6.1097 +        """
  6.1098 +        Logger.__init__(self, "root", level)
  6.1099 +
  6.1100 +_loggerClass = Logger
  6.1101 +
  6.1102 +root = RootLogger(WARNING)
  6.1103 +Logger.root = root
  6.1104 +Logger.manager = Manager(Logger.root)
  6.1105 +
  6.1106 +#---------------------------------------------------------------------------
  6.1107 +# Configuration classes and functions
  6.1108 +#---------------------------------------------------------------------------
  6.1109 +
  6.1110 +BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s"
  6.1111 +
  6.1112 +def basicConfig():
  6.1113 +    """
  6.1114 +    Do basic configuration for the logging system by creating a
  6.1115 +    StreamHandler with a default Formatter and adding it to the
  6.1116 +    root logger.
  6.1117 +    """
  6.1118 +    if len(root.handlers) == 0:
  6.1119 +        hdlr = StreamHandler()
  6.1120 +        fmt = Formatter(BASIC_FORMAT)
  6.1121 +        hdlr.setFormatter(fmt)
  6.1122 +        root.addHandler(hdlr)
  6.1123 +
  6.1124 +#---------------------------------------------------------------------------
  6.1125 +# Utility functions at module level.
  6.1126 +# Basically delegate everything to the root logger.
  6.1127 +#---------------------------------------------------------------------------
  6.1128 +
  6.1129 +def getLogger(name=None):
  6.1130 +    """
  6.1131 +    Return a logger with the specified name, creating it if necessary.
  6.1132 +
  6.1133 +    If no name is specified, return the root logger.
  6.1134 +    """
  6.1135 +    if name:
  6.1136 +        return Logger.manager.getLogger(name)
  6.1137 +    else:
  6.1138 +        return root
  6.1139 +
  6.1140 +#def getRootLogger():
  6.1141 +#    """
  6.1142 +#    Return the root logger.
  6.1143 +#
  6.1144 +#    Note that getLogger('') now does the same thing, so this function is
  6.1145 +#    deprecated and may disappear in the future.
  6.1146 +#    """
  6.1147 +#    return root
  6.1148 +
  6.1149 +def critical(msg, *args, **kwargs):
  6.1150 +    """
  6.1151 +    Log a message with severity 'CRITICAL' on the root logger.
  6.1152 +    """
  6.1153 +    if len(root.handlers) == 0:
  6.1154 +        basicConfig()
  6.1155 +    apply(root.critical, (msg,)+args, kwargs)
  6.1156 +
  6.1157 +fatal = critical
  6.1158 +
  6.1159 +def error(msg, *args, **kwargs):
  6.1160 +    """
  6.1161 +    Log a message with severity 'ERROR' on the root logger.
  6.1162 +    """
  6.1163 +    if len(root.handlers) == 0:
  6.1164 +        basicConfig()
  6.1165 +    apply(root.error, (msg,)+args, kwargs)
  6.1166 +
  6.1167 +def exception(msg, *args):
  6.1168 +    """
  6.1169 +    Log a message with severity 'ERROR' on the root logger,
  6.1170 +    with exception information.
  6.1171 +    """
  6.1172 +    apply(error, (msg,)+args, {'exc_info': 1})
  6.1173 +
  6.1174 +def warning(msg, *args, **kwargs):
  6.1175 +    """
  6.1176 +    Log a message with severity 'WARNING' on the root logger.
  6.1177 +    """
  6.1178 +    if len(root.handlers) == 0:
  6.1179 +        basicConfig()
  6.1180 +    apply(root.warning, (msg,)+args, kwargs)
  6.1181 +
  6.1182 +warn = warning
  6.1183 +
  6.1184 +def info(msg, *args, **kwargs):
  6.1185 +    """
  6.1186 +    Log a message with severity 'INFO' on the root logger.
  6.1187 +    """
  6.1188 +    if len(root.handlers) == 0:
  6.1189 +        basicConfig()
  6.1190 +    apply(root.info, (msg,)+args, kwargs)
  6.1191 +
  6.1192 +def debug(msg, *args, **kwargs):
  6.1193 +    """
  6.1194 +    Log a message with severity 'DEBUG' on the root logger.
  6.1195 +    """
  6.1196 +    if len(root.handlers) == 0:
  6.1197 +        basicConfig()
  6.1198 +    apply(root.debug, (msg,)+args, kwargs)
  6.1199 +
  6.1200 +def disable(level):
  6.1201 +    """
  6.1202 +    Disable all logging calls less severe than 'level'.
  6.1203 +    """
  6.1204 +    root.manager.disable = level
  6.1205 +
  6.1206 +def shutdown():
  6.1207 +    """
  6.1208 +    Perform any cleanup actions in the logging system (e.g. flushing
  6.1209 +    buffers).
  6.1210 +
  6.1211 +    Should be called at application exit.
  6.1212 +    """
  6.1213 +    for h in _handlers.keys():
  6.1214 +        h.flush()
  6.1215 +        h.close()
  6.1216 +
  6.1217 +#Let's try and shutdown automatically on application exit...
  6.1218 +try:
  6.1219 +    import atexit
  6.1220 +    atexit.register(shutdown)
  6.1221 +except ImportError: # for Python versions < 2.0
  6.1222 +    def exithook(status, old_exit=sys.exit):
  6.1223 +        try:
  6.1224 +            shutdown()
  6.1225 +        finally:
  6.1226 +            old_exit(status)
  6.1227 +
  6.1228 +    sys.exit = exithook
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tools/python/logging/logging-0.4.9.2/logging/config.py	Thu Jul 22 13:42:39 2004 +0000
     7.3 @@ -0,0 +1,301 @@
     7.4 +# Copyright 2001-2004 by Vinay Sajip. All Rights Reserved.
     7.5 +#
     7.6 +# Permission to use, copy, modify, and distribute this software and its
     7.7 +# documentation for any purpose and without fee is hereby granted,
     7.8 +# provided that the above copyright notice appear in all copies and that
     7.9 +# both that copyright notice and this permission notice appear in
    7.10 +# supporting documentation, and that the name of Vinay Sajip
    7.11 +# not be used in advertising or publicity pertaining to distribution
    7.12 +# of the software without specific, written prior permission.
    7.13 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    7.14 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
    7.15 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
    7.16 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
    7.17 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
    7.18 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    7.19 +
    7.20 +"""
    7.21 +Configuration functions for the logging package for Python. The core package
    7.22 +is based on PEP 282 and comments thereto in comp.lang.python, and influenced
    7.23 +by Apache's log4j system.
    7.24 +
    7.25 +Should work under Python versions >= 1.5.2, except that source line
    7.26 +information is not available unless 'sys._getframe()' is.
    7.27 +
    7.28 +Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
    7.29 +
    7.30 +To use, simply 'import logging' and log away!
    7.31 +"""
    7.32 +
    7.33 +import sys, logging, logging.handlers, string, thread, threading, socket, struct, os
    7.34 +
    7.35 +from SocketServer import ThreadingTCPServer, StreamRequestHandler
    7.36 +
    7.37 +
    7.38 +DEFAULT_LOGGING_CONFIG_PORT = 9030
    7.39 +
    7.40 +if sys.platform == "win32":
    7.41 +    RESET_ERROR = 10054   #WSAECONNRESET
    7.42 +else:
    7.43 +    RESET_ERROR = 104     #ECONNRESET
    7.44 +
    7.45 +#
    7.46 +#   The following code implements a socket listener for on-the-fly
    7.47 +#   reconfiguration of logging.
    7.48 +#
    7.49 +#   _listener holds the server object doing the listening
    7.50 +_listener = None
    7.51 +
    7.52 +def fileConfig(fname, defaults=None):
    7.53 +    """
    7.54 +    Read the logging configuration from a ConfigParser-format file.
    7.55 +
    7.56 +    This can be called several times from an application, allowing an end user
    7.57 +    the ability to select from various pre-canned configurations (if the
    7.58 +    developer provides a mechanism to present the choices and load the chosen
    7.59 +    configuration).
    7.60 +    In versions of ConfigParser which have the readfp method [typically
    7.61 +    shipped in 2.x versions of Python], you can pass in a file-like object
    7.62 +    rather than a filename, in which case the file-like object will be read
    7.63 +    using readfp.
    7.64 +    """
    7.65 +    import ConfigParser
    7.66 +
    7.67 +    cp = ConfigParser.ConfigParser(defaults)
    7.68 +    if hasattr(cp, 'readfp') and hasattr(fname, 'readline'):
    7.69 +        cp.readfp(fname)
    7.70 +    else:
    7.71 +        cp.read(fname)
    7.72 +    #first, do the formatters...
    7.73 +    flist = cp.get("formatters", "keys")
    7.74 +    if len(flist):
    7.75 +        flist = string.split(flist, ",")
    7.76 +        formatters = {}
    7.77 +        for form in flist:
    7.78 +            sectname = "formatter_%s" % form
    7.79 +            opts = cp.options(sectname)
    7.80 +            if "format" in opts:
    7.81 +                fs = cp.get(sectname, "format", 1)
    7.82 +            else:
    7.83 +                fs = None
    7.84 +            if "datefmt" in opts:
    7.85 +                dfs = cp.get(sectname, "datefmt", 1)
    7.86 +            else:
    7.87 +                dfs = None
    7.88 +            f = logging.Formatter(fs, dfs)
    7.89 +            formatters[form] = f
    7.90 +    #next, do the handlers...
    7.91 +    #critical section...
    7.92 +    logging._acquireLock()
    7.93 +    try:
    7.94 +        try:
    7.95 +            #first, lose the existing handlers...
    7.96 +            logging._handlers.clear()
    7.97 +            #now set up the new ones...
    7.98 +            hlist = cp.get("handlers", "keys")
    7.99 +            if len(hlist):
   7.100 +                hlist = string.split(hlist, ",")
   7.101 +                handlers = {}
   7.102 +                fixups = [] #for inter-handler references
   7.103 +                for hand in hlist:
   7.104 +                    sectname = "handler_%s" % hand
   7.105 +                    klass = cp.get(sectname, "class")
   7.106 +                    opts = cp.options(sectname)
   7.107 +                    if "formatter" in opts:
   7.108 +                        fmt = cp.get(sectname, "formatter")
   7.109 +                    else:
   7.110 +                        fmt = ""
   7.111 +                    klass = eval(klass, vars(logging))
   7.112 +                    args = cp.get(sectname, "args")
   7.113 +                    args = eval(args, vars(logging))
   7.114 +                    h = apply(klass, args)
   7.115 +                    if "level" in opts:
   7.116 +                        level = cp.get(sectname, "level")
   7.117 +                        h.setLevel(logging._levelNames[level])
   7.118 +                    if len(fmt):
   7.119 +                        h.setFormatter(formatters[fmt])
   7.120 +                    #temporary hack for FileHandler and MemoryHandler.
   7.121 +                    if klass == logging.handlers.MemoryHandler:
   7.122 +                        if "target" in opts:
   7.123 +                            target = cp.get(sectname,"target")
   7.124 +                        else:
   7.125 +                            target = ""
   7.126 +                        if len(target): #the target handler may not be loaded yet, so keep for later...
   7.127 +                            fixups.append((h, target))
   7.128 +                    handlers[hand] = h
   7.129 +                #now all handlers are loaded, fixup inter-handler references...
   7.130 +                for fixup in fixups:
   7.131 +                    h = fixup[0]
   7.132 +                    t = fixup[1]
   7.133 +                    h.setTarget(handlers[t])
   7.134 +            #at last, the loggers...first the root...
   7.135 +            llist = cp.get("loggers", "keys")
   7.136 +            llist = string.split(llist, ",")
   7.137 +            llist.remove("root")
   7.138 +            sectname = "logger_root"
   7.139 +            root = logging.root
   7.140 +            log = root
   7.141 +            opts = cp.options(sectname)
   7.142 +            if "level" in opts:
   7.143 +                level = cp.get(sectname, "level")
   7.144 +                log.setLevel(logging._levelNames[level])
   7.145 +            for h in root.handlers[:]:
   7.146 +                root.removeHandler(h)
   7.147 +            hlist = cp.get(sectname, "handlers")
   7.148 +            if len(hlist):
   7.149 +                hlist = string.split(hlist, ",")
   7.150 +                for hand in hlist:
   7.151 +                    log.addHandler(handlers[hand])
   7.152 +            #and now the others...
   7.153 +            #we don't want to lose the existing loggers,
   7.154 +            #since other threads may have pointers to them.
   7.155 +            #existing is set to contain all existing loggers,
   7.156 +            #and as we go through the new configuration we
   7.157 +            #remove any which are configured. At the end,
   7.158 +            #what's left in existing is the set of loggers
   7.159 +            #which were in the previous configuration but
   7.160 +            #which are not in the new configuration.
   7.161 +            existing = root.manager.loggerDict.keys()
   7.162 +            #now set up the new ones...
   7.163 +            for log in llist:
   7.164 +                sectname = "logger_%s" % log
   7.165 +                qn = cp.get(sectname, "qualname")
   7.166 +                opts = cp.options(sectname)
   7.167 +                if "propagate" in opts:
   7.168 +                    propagate = cp.getint(sectname, "propagate")
   7.169 +                else:
   7.170 +                    propagate = 1
   7.171 +                logger = logging.getLogger(qn)
   7.172 +                if qn in existing:
   7.173 +                    existing.remove(qn)
   7.174 +                if "level" in opts:
   7.175 +                    level = cp.get(sectname, "level")
   7.176 +                    logger.setLevel(logging._levelNames[level])
   7.177 +                for h in logger.handlers[:]:
   7.178 +                    logger.removeHandler(h)
   7.179 +                logger.propagate = propagate
   7.180 +                logger.disabled = 0
   7.181 +                hlist = cp.get(sectname, "handlers")
   7.182 +                if len(hlist):
   7.183 +                    hlist = string.split(hlist, ",")
   7.184 +                    for hand in hlist:
   7.185 +                        logger.addHandler(handlers[hand])
   7.186 +            #Disable any old loggers. There's no point deleting
   7.187 +            #them as other threads may continue to hold references
   7.188 +            #and by disabling them, you stop them doing any logging.
   7.189 +            for log in existing:
   7.190 +                root.manager.loggerDict[log].disabled = 1
   7.191 +        except:
   7.192 +            import traceback
   7.193 +            ei = sys.exc_info()
   7.194 +            traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
   7.195 +            del ei
   7.196 +    finally:
   7.197 +        logging._releaseLock()
   7.198 +
   7.199 +def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
   7.200 +    """
   7.201 +    Start up a socket server on the specified port, and listen for new
   7.202 +    configurations.
   7.203 +
   7.204 +    These will be sent as a file suitable for processing by fileConfig().
   7.205 +    Returns a Thread object on which you can call start() to start the server,
   7.206 +    and which you can join() when appropriate. To stop the server, call
   7.207 +    stopListening().
   7.208 +    """
   7.209 +    if not thread:
   7.210 +        raise NotImplementedError, "listen() needs threading to work"
   7.211 +
   7.212 +    class ConfigStreamHandler(StreamRequestHandler):
   7.213 +        """
   7.214 +        Handler for a logging configuration request.
   7.215 +
   7.216 +        It expects a completely new logging configuration and uses fileConfig
   7.217 +        to install it.
   7.218 +        """
   7.219 +        def handle(self):
   7.220 +            """
   7.221 +            Handle a request.
   7.222 +
   7.223 +            Each request is expected to be a 4-byte length,
   7.224 +            followed by the config file. Uses fileConfig() to do the
   7.225 +            grunt work.
   7.226 +            """
   7.227 +            import tempfile
   7.228 +            try:
   7.229 +                conn = self.connection
   7.230 +                chunk = conn.recv(4)
   7.231 +                if len(chunk) == 4:
   7.232 +                    slen = struct.unpack(">L", chunk)[0]
   7.233 +                    chunk = self.connection.recv(slen)
   7.234 +                    while len(chunk) < slen:
   7.235 +                        chunk = chunk + conn.recv(slen - len(chunk))
   7.236 +                    #Apply new configuration. We'd like to be able to
   7.237 +                    #create a StringIO and pass that in, but unfortunately
   7.238 +                    #1.5.2 ConfigParser does not support reading file
   7.239 +                    #objects, only actual files. So we create a temporary
   7.240 +                    #file and remove it later.
   7.241 +                    file = tempfile.mktemp(".ini")
   7.242 +                    f = open(file, "w")
   7.243 +                    f.write(chunk)
   7.244 +                    f.close()
   7.245 +                    fileConfig(file)
   7.246 +                    os.remove(file)
   7.247 +            except socket.error, e:
   7.248 +                if type(e.args) != types.TupleType:
   7.249 +                    raise
   7.250 +                else:
   7.251 +                    errcode = e.args[0]
   7.252 +                    if errcode != RESET_ERROR:
   7.253 +                        raise
   7.254 +
   7.255 +    class ConfigSocketReceiver(ThreadingTCPServer):
   7.256 +        """
   7.257 +        A simple TCP socket-based logging config receiver.
   7.258 +        """
   7.259 +
   7.260 +        allow_reuse_address = 1
   7.261 +
   7.262 +        def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT,
   7.263 +                     handler=None):
   7.264 +            ThreadingTCPServer.__init__(self, (host, port), handler)
   7.265 +            logging._acquireLock()
   7.266 +            self.abort = 0
   7.267 +            logging._releaseLock()
   7.268 +            self.timeout = 1
   7.269 +
   7.270 +        def serve_until_stopped(self):
   7.271 +            import select
   7.272 +            abort = 0
   7.273 +            while not abort:
   7.274 +                rd, wr, ex = select.select([self.socket.fileno()],
   7.275 +                                           [], [],
   7.276 +                                           self.timeout)
   7.277 +                if rd:
   7.278 +                    self.handle_request()
   7.279 +                logging._acquireLock()
   7.280 +                abort = self.abort
   7.281 +                logging._releaseLock()
   7.282 +
   7.283 +    def serve(rcvr, hdlr, port):
   7.284 +        server = rcvr(port=port, handler=hdlr)
   7.285 +        global _listener
   7.286 +        logging._acquireLock()
   7.287 +        _listener = server
   7.288 +        logging._releaseLock()
   7.289 +        server.serve_until_stopped()
   7.290 +
   7.291 +    return threading.Thread(target=serve,
   7.292 +                            args=(ConfigSocketReceiver,
   7.293 +                                  ConfigStreamHandler, port))
   7.294 +
   7.295 +def stopListening():
   7.296 +    """
   7.297 +    Stop the listening server which was created with a call to listen().
   7.298 +    """
   7.299 +    global _listener
   7.300 +    if _listener:
   7.301 +        logging._acquireLock()
   7.302 +        _listener.abort = 1
   7.303 +        _listener = None
   7.304 +        logging._releaseLock()
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/python/logging/logging-0.4.9.2/logging/handlers.py	Thu Jul 22 13:42:39 2004 +0000
     8.3 @@ -0,0 +1,787 @@
     8.4 +# Copyright 2001-2004 by Vinay Sajip. All Rights Reserved.
     8.5 +#
     8.6 +# Permission to use, copy, modify, and distribute this software and its
     8.7 +# documentation for any purpose and without fee is hereby granted,
     8.8 +# provided that the above copyright notice appear in all copies and that
     8.9 +# both that copyright notice and this permission notice appear in
    8.10 +# supporting documentation, and that the name of Vinay Sajip
    8.11 +# not be used in advertising or publicity pertaining to distribution
    8.12 +# of the software without specific, written prior permission.
    8.13 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    8.14 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
    8.15 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
    8.16 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
    8.17 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
    8.18 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    8.19 +
    8.20 +"""
    8.21 +Additional handlers for the logging package for Python. The core package is
    8.22 +based on PEP 282 and comments thereto in comp.lang.python, and influenced by
    8.23 +Apache's log4j system.
    8.24 +
    8.25 +Should work under Python versions >= 1.5.2, except that source line
    8.26 +information is not available unless 'sys._getframe()' is.
    8.27 +
    8.28 +Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
    8.29 +
    8.30 +To use, simply 'import logging' and log away!
    8.31 +"""
    8.32 +
    8.33 +import sys, logging, socket, types, os, string, cPickle, struct, time
    8.34 +
    8.35 +from SocketServer import ThreadingTCPServer, StreamRequestHandler
    8.36 +
    8.37 +#
    8.38 +# Some constants...
    8.39 +#
    8.40 +
    8.41 +DEFAULT_TCP_LOGGING_PORT    = 9020
    8.42 +DEFAULT_UDP_LOGGING_PORT    = 9021
    8.43 +DEFAULT_HTTP_LOGGING_PORT   = 9022
    8.44 +DEFAULT_SOAP_LOGGING_PORT   = 9023
    8.45 +SYSLOG_UDP_PORT             = 514
    8.46 +
    8.47 +
    8.48 +class RotatingFileHandler(logging.FileHandler):
    8.49 +    def __init__(self, filename, mode="a", maxBytes=0, backupCount=0):
    8.50 +        """
    8.51 +        Open the specified file and use it as the stream for logging.
    8.52 +
    8.53 +        By default, the file grows indefinitely. You can specify particular
    8.54 +        values of maxBytes and backupCount to allow the file to rollover at
    8.55 +        a predetermined size.
    8.56 +
    8.57 +        Rollover occurs whenever the current log file is nearly maxBytes in
    8.58 +        length. If backupCount is >= 1, the system will successively create
    8.59 +        new files with the same pathname as the base file, but with extensions
    8.60 +        ".1", ".2" etc. appended to it. For example, with a backupCount of 5
    8.61 +        and a base file name of "app.log", you would get "app.log",
    8.62 +        "app.log.1", "app.log.2", ... through to "app.log.5". The file being
    8.63 +        written to is always "app.log" - when it gets filled up, it is closed
    8.64 +        and renamed to "app.log.1", and if files "app.log.1", "app.log.2" etc.
    8.65 +        exist, then they are renamed to "app.log.2", "app.log.3" etc.
    8.66 +        respectively.
    8.67 +
    8.68 +        If maxBytes is zero, rollover never occurs.
    8.69 +        """
    8.70 +        logging.FileHandler.__init__(self, filename, mode)
    8.71 +        self.maxBytes = maxBytes
    8.72 +        self.backupCount = backupCount
    8.73 +        if maxBytes > 0:
    8.74 +            self.mode = "a"
    8.75 +
    8.76 +    def doRollover(self):
    8.77 +        """
    8.78 +        Do a rollover, as described in __init__().
    8.79 +        """
    8.80 +
    8.81 +        self.stream.close()
    8.82 +        if self.backupCount > 0:
    8.83 +            for i in range(self.backupCount - 1, 0, -1):
    8.84 +                sfn = "%s.%d" % (self.baseFilename, i)
    8.85 +                dfn = "%s.%d" % (self.baseFilename, i + 1)
    8.86 +                if os.path.exists(sfn):
    8.87 +                    #print "%s -> %s" % (sfn, dfn)
    8.88 +                    if os.path.exists(dfn):
    8.89 +                        os.remove(dfn)
    8.90 +                    os.rename(sfn, dfn)
    8.91 +            dfn = self.baseFilename + ".1"
    8.92 +            if os.path.exists(dfn):
    8.93 +                os.remove(dfn)
    8.94 +            os.rename(self.baseFilename, dfn)
    8.95 +            #print "%s -> %s" % (self.baseFilename, dfn)
    8.96 +        self.stream = open(self.baseFilename, "w")
    8.97 +
    8.98 +    def emit(self, record):
    8.99 +        """
   8.100 +        Emit a record.
   8.101 +
   8.102 +        Output the record to the file, catering for rollover as described
   8.103 +        in doRollover().
   8.104 +        """
   8.105 +        if self.maxBytes > 0:                   # are we rolling over?
   8.106 +            msg = "%s\n" % self.format(record)
   8.107 +            self.stream.seek(0, 2)  #due to non-posix-compliant Windows feature
   8.108 +            if self.stream.tell() + len(msg) >= self.maxBytes:
   8.109 +                self.doRollover()
   8.110 +        logging.FileHandler.emit(self, record)
   8.111 +
   8.112 +
   8.113 +class SocketHandler(logging.Handler):
   8.114 +    """
   8.115 +    A handler class which writes logging records, in pickle format, to
   8.116 +    a streaming socket. The socket is kept open across logging calls.
   8.117 +    If the peer resets it, an attempt is made to reconnect on the next call.
   8.118 +    The pickle which is sent is that of the LogRecord's attribute dictionary
   8.119 +    (__dict__), so that the receiver does not need to have the logging module
   8.120 +    installed in order to process the logging event.
   8.121 +
   8.122 +    To unpickle the record at the receiving end into a LogRecord, use the
   8.123 +    makeLogRecord function.
   8.124 +    """
   8.125 +
   8.126 +    def __init__(self, host, port):
   8.127 +        """
   8.128 +        Initializes the handler with a specific host address and port.
   8.129 +
   8.130 +        The attribute 'closeOnError' is set to 1 - which means that if
   8.131 +        a socket error occurs, the socket is silently closed and then
   8.132 +        reopened on the next logging call.
   8.133 +        """
   8.134 +        logging.Handler.__init__(self)
   8.135 +        self.host = host
   8.136 +        self.port = port
   8.137 +        self.sock = None
   8.138 +        self.closeOnError = 0
   8.139 +        self.retryTime = None
   8.140 +        #
   8.141 +        # Exponential backoff parameters.
   8.142 +        #
   8.143 +        self.retryStart = 1.0
   8.144 +        self.retryMax = 30.0
   8.145 +        self.retryFactor = 2.0
   8.146 +
   8.147 +    def makeSocket(self):
   8.148 +        """
   8.149 +        A factory method which allows subclasses to define the precise
   8.150 +        type of socket they want.
   8.151 +        """
   8.152 +        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   8.153 +        s.connect((self.host, self.port))
   8.154 +        return s
   8.155 +
   8.156 +    def createSocket(self):
   8.157 +        """
   8.158 +        Try to create a socket, using an exponential backoff with
   8.159 +        a max retry time. Thanks to Robert Olson for the original patch
   8.160 +        (SF #815911) which has been slightly refactored.
   8.161 +        """
   8.162 +        now = time.time()
   8.163 +        # Either retryTime is None, in which case this
   8.164 +        # is the first time back after a disconnect, or
   8.165 +        # we've waited long enough.
   8.166 +        if self.retryTime is None:
   8.167 +          attempt = 1
   8.168 +        else:
   8.169 +          attempt = (now >= self.retryTime)
   8.170 +        if attempt:
   8.171 +            try:
   8.172 +                self.sock = self.makeSocket()
   8.173 +                self.retryTime = None # next time, no delay before trying
   8.174 +            except:
   8.175 +                #Creation failed, so set the retry time and return.
   8.176 +                if self.retryTime is None:
   8.177 +                    self.retryPeriod = self.retryStart
   8.178 +                else:
   8.179 +                    self.retryPeriod = self.retryPeriod * self.retryFactor
   8.180 +                    if self.retryPeriod > self.retryMax:
   8.181 +                        self.retryPeriod = self.retryMax
   8.182 +                self.retryTime = now + self.retryPeriod
   8.183 +
   8.184 +    def send(self, s):
   8.185 +        """
   8.186 +        Send a pickled string to the socket.
   8.187 +
   8.188 +        This function allows for partial sends which can happen when the
   8.189 +        network is busy.
   8.190 +        """
   8.191 +        if self.sock is None:
   8.192 +            self.createSocket()
   8.193 +        #self.sock can be None either because we haven't reached the retry
   8.194 +        #time yet, or because we have reached the retry time and retried,
   8.195 +        #but are still unable to connect.
   8.196 +        if self.sock:
   8.197 +            try:
   8.198 +                if hasattr(self.sock, "sendall"):
   8.199 +                    self.sock.sendall(s)
   8.200 +                else:
   8.201 +                    sentsofar = 0
   8.202 +                    left = len(s)
   8.203 +                    while left > 0:
   8.204 +                        sent = self.sock.send(s[sentsofar:])
   8.205 +                        sentsofar = sentsofar + sent
   8.206 +                        left = left - sent
   8.207 +            except socket.error:
   8.208 +                self.sock.close()
   8.209 +                self.sock = None  # so we can call createSocket next time
   8.210 +
   8.211 +    def makePickle(self, record):
   8.212 +        """
   8.213 +        Pickles the record in binary format with a length prefix, and
   8.214 +        returns it ready for transmission across the socket.
   8.215 +        """
   8.216 +        ei = record.exc_info
   8.217 +        if ei:
   8.218 +          dummy = self.format(record) # just to get traceback text into record.exc_text
   8.219 +          record.exc_info = None  # to avoid Unpickleable error
   8.220 +        s = cPickle.dumps(record.__dict__, 1)
   8.221 +        if ei:
   8.222 +          record.exc_info = ei  # for next handler
   8.223 +        slen = struct.pack(">L", len(s))
   8.224 +        return slen + s
   8.225 +
   8.226 +    def handleError(self, record):
   8.227 +        """
   8.228 +        Handle an error during logging.
   8.229 +
   8.230 +        An error has occurred during logging. Most likely cause -
   8.231 +        connection lost. Close the socket so that we can retry on the
   8.232 +        next event.
   8.233 +        """
   8.234 +        if self.closeOnError and self.sock:
   8.235 +            self.sock.close()
   8.236 +            self.sock = None        #try to reconnect next time
   8.237 +        else:
   8.238 +            logging.Handler.handleError(self, record)
   8.239 +
   8.240 +    def emit(self, record):
   8.241 +        """
   8.242 +        Emit a record.
   8.243 +
   8.244 +        Pickles the record and writes it to the socket in binary format.
   8.245 +        If there is an error with the socket, silently drop the packet.
   8.246 +        If there was a problem with the socket, re-establishes the
   8.247 +        socket.
   8.248 +        """
   8.249 +        try:
   8.250 +            s = self.makePickle(record)
   8.251 +            self.send(s)
   8.252 +        except:
   8.253 +            self.handleError(record)
   8.254 +
   8.255 +    def close(self):
   8.256 +        """
   8.257 +        Closes the socket.
   8.258 +        """
   8.259 +        if self.sock:
   8.260 +            self.sock.close()
   8.261 +            self.sock = None
   8.262 +        logging.Handler.close(self)
   8.263 +
   8.264 +class DatagramHandler(SocketHandler):
   8.265 +    """
   8.266 +    A handler class which writes logging records, in pickle format, to
   8.267 +    a datagram socket.  The pickle which is sent is that of the LogRecord's
   8.268 +    attribute dictionary (__dict__), so that the receiver does not need to
   8.269 +    have the logging module installed in order to process the logging event.
   8.270 +
   8.271 +    To unpickle the record at the receiving end into a LogRecord, use the
   8.272 +    makeLogRecord function.
   8.273 +
   8.274 +    """
   8.275 +    def __init__(self, host, port):
   8.276 +        """
   8.277 +        Initializes the handler with a specific host address and port.
   8.278 +        """
   8.279 +        SocketHandler.__init__(self, host, port)
   8.280 +        self.closeOnError = 0
   8.281 +
   8.282 +    def makeSocket(self):
   8.283 +        """
   8.284 +        The factory method of SocketHandler is here overridden to create
   8.285 +        a UDP socket (SOCK_DGRAM).
   8.286 +        """
   8.287 +        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   8.288 +        return s
   8.289 +
   8.290 +    def send(self, s):
   8.291 +        """
   8.292 +        Send a pickled string to a socket.
   8.293 +
   8.294 +        This function no longer allows for partial sends which can happen
   8.295 +        when the network is busy - UDP does not guarantee delivery and
   8.296 +        can deliver packets out of sequence.
   8.297 +        """
   8.298 +        self.sock.sendto(s, (self.host, self.port))
   8.299 +
   8.300 +class SysLogHandler(logging.Handler):
   8.301 +    """
   8.302 +    A handler class which sends formatted logging records to a syslog
   8.303 +    server. Based on Sam Rushing's syslog module:
   8.304 +    http://www.nightmare.com/squirl/python-ext/misc/syslog.py
   8.305 +    Contributed by Nicolas Untz (after which minor refactoring changes
   8.306 +    have been made).
   8.307 +    """
   8.308 +
   8.309 +    # from <linux/sys/syslog.h>:
   8.310 +    # ======================================================================
   8.311 +    # priorities/facilities are encoded into a single 32-bit quantity, where
   8.312 +    # the bottom 3 bits are the priority (0-7) and the top 28 bits are the
   8.313 +    # facility (0-big number). Both the priorities and the facilities map
   8.314 +    # roughly one-to-one to strings in the syslogd(8) source code.  This
   8.315 +    # mapping is included in this file.
   8.316 +    #
   8.317 +    # priorities (these are ordered)
   8.318 +
   8.319 +    LOG_EMERG     = 0       #  system is unusable
   8.320 +    LOG_ALERT     = 1       #  action must be taken immediately
   8.321 +    LOG_CRIT      = 2       #  critical conditions
   8.322 +    LOG_ERR       = 3       #  error conditions
   8.323 +    LOG_WARNING   = 4       #  warning conditions
   8.324 +    LOG_NOTICE    = 5       #  normal but significant condition
   8.325 +    LOG_INFO      = 6       #  informational
   8.326 +    LOG_DEBUG     = 7       #  debug-level messages
   8.327 +
   8.328 +    #  facility codes
   8.329 +    LOG_KERN      = 0       #  kernel messages
   8.330 +    LOG_USER      = 1       #  random user-level messages
   8.331 +    LOG_MAIL      = 2       #  mail system
   8.332 +    LOG_DAEMON    = 3       #  system daemons
   8.333 +    LOG_AUTH      = 4       #  security/authorization messages
   8.334 +    LOG_SYSLOG    = 5       #  messages generated internally by syslogd
   8.335 +    LOG_LPR       = 6       #  line printer subsystem
   8.336 +    LOG_NEWS      = 7       #  network news subsystem
   8.337 +    LOG_UUCP      = 8       #  UUCP subsystem
   8.338 +    LOG_CRON      = 9       #  clock daemon
   8.339 +    LOG_AUTHPRIV  = 10  #  security/authorization messages (private)
   8.340 +
   8.341 +    #  other codes through 15 reserved for system use
   8.342 +    LOG_LOCAL0    = 16      #  reserved for local use
   8.343 +    LOG_LOCAL1    = 17      #  reserved for local use
   8.344 +    LOG_LOCAL2    = 18      #  reserved for local use
   8.345 +    LOG_LOCAL3    = 19      #  reserved for local use
   8.346 +    LOG_LOCAL4    = 20      #  reserved for local use
   8.347 +    LOG_LOCAL5    = 21      #  reserved for local use
   8.348 +    LOG_LOCAL6    = 22      #  reserved for local use
   8.349 +    LOG_LOCAL7    = 23      #  reserved for local use
   8.350 +
   8.351 +    priority_names = {
   8.352 +        "alert":    LOG_ALERT,
   8.353 +        "crit":     LOG_CRIT,
   8.354 +        "critical": LOG_CRIT,
   8.355 +        "debug":    LOG_DEBUG,
   8.356 +        "emerg":    LOG_EMERG,
   8.357 +        "err":      LOG_ERR,
   8.358 +        "error":    LOG_ERR,        #  DEPRECATED
   8.359 +        "info":     LOG_INFO,
   8.360 +        "notice":   LOG_NOTICE,
   8.361 +        "panic":    LOG_EMERG,      #  DEPRECATED
   8.362 +        "warn":     LOG_WARNING,    #  DEPRECATED
   8.363 +        "warning":  LOG_WARNING,
   8.364 +        }
   8.365 +
   8.366 +    facility_names = {
   8.367 +        "auth":     LOG_AUTH,
   8.368 +        "authpriv": LOG_AUTHPRIV,
   8.369 +        "cron":     LOG_CRON,
   8.370 +        "daemon":   LOG_DAEMON,
   8.371 +        "kern":     LOG_KERN,
   8.372 +        "lpr":      LOG_LPR,
   8.373 +        "mail":     LOG_MAIL,
   8.374 +        "news":     LOG_NEWS,
   8.375 +        "security": LOG_AUTH,       #  DEPRECATED
   8.376 +        "syslog":   LOG_SYSLOG,
   8.377 +        "user":     LOG_USER,
   8.378 +        "uucp":     LOG_UUCP,
   8.379 +        "local0":   LOG_LOCAL0,
   8.380 +        "local1":   LOG_LOCAL1,
   8.381 +        "local2":   LOG_LOCAL2,
   8.382 +        "local3":   LOG_LOCAL3,
   8.383 +        "local4":   LOG_LOCAL4,
   8.384 +        "local5":   LOG_LOCAL5,
   8.385 +        "local6":   LOG_LOCAL6,
   8.386 +        "local7":   LOG_LOCAL7,
   8.387 +        }
   8.388 +
   8.389 +    def __init__(self, address=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER):
   8.390 +        """
   8.391 +        Initialize a handler.
   8.392 +
   8.393 +        If address is specified as a string, UNIX socket is used.
   8.394 +        If facility is not specified, LOG_USER is used.
   8.395 +        """
   8.396 +        logging.Handler.__init__(self)
   8.397 +
   8.398 +        self.address = address
   8.399 +        self.facility = facility
   8.400 +        if type(address) == types.StringType:
   8.401 +            self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
   8.402 +            # syslog may require either DGRAM or STREAM sockets
   8.403 +            try:
   8.404 +                self.socket.connect(address)
   8.405 +            except socket.error:
   8.406 +                self.socket.close()
   8.407 +                self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
   8.408 +            self.socket.connect(address)
   8.409 +            self.unixsocket = 1
   8.410 +        else:
   8.411 +            self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   8.412 +            self.unixsocket = 0
   8.413 +
   8.414 +        self.formatter = None
   8.415 +
   8.416 +    # curious: when talking to the unix-domain '/dev/log' socket, a
   8.417 +    #   zero-terminator seems to be required.  this string is placed
   8.418 +    #   into a class variable so that it can be overridden if
   8.419 +    #   necessary.
   8.420 +    log_format_string = '<%d>%s\000'
   8.421 +
   8.422 +    def encodePriority (self, facility, priority):
   8.423 +        """
   8.424 +        Encode the facility and priority. You can pass in strings or
   8.425 +        integers - if strings are passed, the facility_names and
   8.426 +        priority_names mapping dictionaries are used to convert them to
   8.427 +        integers.
   8.428 +        """
   8.429 +        if type(facility) == types.StringType:
   8.430 +            facility = self.facility_names[facility]
   8.431 +        if type(priority) == types.StringType:
   8.432 +            priority = self.priority_names[priority]
   8.433 +        return (facility << 3) | priority
   8.434 +
   8.435 +    def close (self):
   8.436 +        """
   8.437 +        Closes the socket.
   8.438 +        """
   8.439 +        if self.unixsocket:
   8.440 +            self.socket.close()
   8.441 +        logging.Handler.close(self)
   8.442 +
   8.443 +    def emit(self, record):
   8.444 +        """
   8.445 +        Emit a record.
   8.446 +
   8.447 +        The record is formatted, and then sent to the syslog server. If
   8.448 +        exception information is present, it is NOT sent to the server.
   8.449 +        """
   8.450 +        msg = self.format(record)
   8.451 +        """
   8.452 +        We need to convert record level to lowercase, maybe this will
   8.453 +        change in the future.
   8.454 +        """
   8.455 +        msg = self.log_format_string % (
   8.456 +            self.encodePriority(self.facility,
   8.457 +                                string.lower(record.levelname)),
   8.458 +            msg)
   8.459 +        try:
   8.460 +            if self.unixsocket:
   8.461 +                self.socket.send(msg)
   8.462 +            else:
   8.463 +                self.socket.sendto(msg, self.address)
   8.464 +        except:
   8.465 +            self.handleError(record)
   8.466 +
   8.467 +class SMTPHandler(logging.Handler):
   8.468 +    """
   8.469 +    A handler class which sends an SMTP email for each logging event.
   8.470 +    """
   8.471 +    def __init__(self, mailhost, fromaddr, toaddrs, subject):
   8.472 +        """
   8.473 +        Initialize the handler.
   8.474 +
   8.475 +        Initialize the instance with the from and to addresses and subject
   8.476 +        line of the email. To specify a non-standard SMTP port, use the
   8.477 +        (host, port) tuple format for the mailhost argument.
   8.478 +        """
   8.479 +        logging.Handler.__init__(self)
   8.480 +        if type(mailhost) == types.TupleType:
   8.481 +            host, port = mailhost
   8.482 +            self.mailhost = host
   8.483 +            self.mailport = port
   8.484 +        else:
   8.485 +            self.mailhost = mailhost
   8.486 +            self.mailport = None
   8.487 +        self.fromaddr = fromaddr
   8.488 +        if type(toaddrs) == types.StringType:
   8.489 +            toaddrs = [toaddrs]
   8.490 +        self.toaddrs = toaddrs
   8.491 +        self.subject = subject
   8.492 +
   8.493 +    def getSubject(self, record):
   8.494 +        """
   8.495 +        Determine the subject for the email.
   8.496 +
   8.497 +        If you want to specify a subject line which is record-dependent,
   8.498 +        override this method.
   8.499 +        """
   8.500 +        return self.subject
   8.501 +
   8.502 +    weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
   8.503 +
   8.504 +    monthname = [None,
   8.505 +                 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
   8.506 +                 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
   8.507 +
   8.508 +    def date_time(self):
   8.509 +        """Return the current date and time formatted for a MIME header."""
   8.510 +        year, month, day, hh, mm, ss, wd, y, z = time.gmtime(time.time())
   8.511 +        s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
   8.512 +                self.weekdayname[wd],
   8.513 +                day, self.monthname[month], year,
   8.514 +                hh, mm, ss)
   8.515 +        return s
   8.516 +
   8.517 +    def emit(self, record):
   8.518 +        """
   8.519 +        Emit a record.
   8.520 +
   8.521 +        Format the record and send it to the specified addressees.
   8.522 +        """
   8.523 +        try:
   8.524 +            import smtplib
   8.525 +            port = self.mailport
   8.526 +            if not port:
   8.527 +                port = smtplib.SMTP_PORT
   8.528 +            smtp = smtplib.SMTP(self.mailhost, port)
   8.529 +            msg = self.format(record)
   8.530 +            msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
   8.531 +                            self.fromaddr,
   8.532 +                            string.join(self.toaddrs, ","),
   8.533 +                            self.getSubject(record),
   8.534 +                            self.date_time(), msg)
   8.535 +            smtp.sendmail(self.fromaddr, self.toaddrs, msg)
   8.536 +            smtp.quit()
   8.537 +        except:
   8.538 +            self.handleError(record)
   8.539 +
   8.540 +class NTEventLogHandler(logging.Handler):
   8.541 +    """
   8.542 +    A handler class which sends events to the NT Event Log. Adds a
   8.543 +    registry entry for the specified application name. If no dllname is
   8.544 +    provided, win32service.pyd (which contains some basic message
   8.545 +    placeholders) is used. Note that use of these placeholders will make
   8.546 +    your event logs big, as the entire message source is held in the log.
   8.547 +    If you want slimmer logs, you have to pass in the name of your own DLL
   8.548 +    which contains the message definitions you want to use in the event log.
   8.549 +    """
   8.550 +    def __init__(self, appname, dllname=None, logtype="Application"):
   8.551 +        logging.Handler.__init__(self)
   8.552 +        try:
   8.553 +            import win32evtlogutil, win32evtlog
   8.554 +            self.appname = appname
   8.555 +            self._welu = win32evtlogutil
   8.556 +            if not dllname:
   8.557 +                dllname = os.path.split(self._welu.__file__)
   8.558 +                dllname = os.path.split(dllname[0])
   8.559 +                dllname = os.path.join(dllname[0], r'win32service.pyd')
   8.560 +            self.dllname = dllname
   8.561 +            self.logtype = logtype
   8.562 +            self._welu.AddSourceToRegistry(appname, dllname, logtype)
   8.563 +            self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE
   8.564 +            self.typemap = {
   8.565 +                logging.DEBUG   : win32evtlog.EVENTLOG_INFORMATION_TYPE,
   8.566 +                logging.INFO    : win32evtlog.EVENTLOG_INFORMATION_TYPE,
   8.567 +                logging.WARNING : win32evtlog.EVENTLOG_WARNING_TYPE,
   8.568 +                logging.ERROR   : win32evtlog.EVENTLOG_ERROR_TYPE,
   8.569 +                logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
   8.570 +         }
   8.571 +        except ImportError:
   8.572 +            print "The Python Win32 extensions for NT (service, event "\
   8.573 +                        "logging) appear not to be available."
   8.574 +            self._welu = None
   8.575 +
   8.576 +    def getMessageID(self, record):
   8.577 +        """
   8.578 +        Return the message ID for the event record. If you are using your
   8.579 +        own messages, you could do this by having the msg passed to the
   8.580 +        logger being an ID rather than a formatting string. Then, in here,
   8.581 +        you could use a dictionary lookup to get the message ID. This
   8.582 +        version returns 1, which is the base message ID in win32service.pyd.
   8.583 +        """
   8.584 +        return 1
   8.585 +
   8.586 +    def getEventCategory(self, record):
   8.587 +        """
   8.588 +        Return the event category for the record.
   8.589 +
   8.590 +        Override this if you want to specify your own categories. This version
   8.591 +        returns 0.
   8.592 +        """
   8.593 +        return 0
   8.594 +
   8.595 +    def getEventType(self, record):
   8.596 +        """
   8.597 +        Return the event type for the record.
   8.598 +
   8.599 +        Override this if you want to specify your own types. This version does
   8.600 +        a mapping using the handler's typemap attribute, which is set up in
   8.601 +        __init__() to a dictionary which contains mappings for DEBUG, INFO,
   8.602 +        WARNING, ERROR and CRITICAL. If you are using your own levels you will
   8.603 +        either need to override this method or place a suitable dictionary in
   8.604 +        the handler's typemap attribute.
   8.605 +        """
   8.606 +        return self.typemap.get(record.levelno, self.deftype)
   8.607 +
   8.608 +    def emit(self, record):
   8.609 +        """
   8.610 +        Emit a record.
   8.611 +
   8.612 +        Determine the message ID, event category and event type. Then
   8.613 +        log the message in the NT event log.
   8.614 +        """
   8.615 +        if self._welu:
   8.616 +            try:
   8.617 +                id = self.getMessageID(record)
   8.618 +                cat = self.getEventCategory(record)
   8.619 +                type = self.getEventType(record)
   8.620 +                msg = self.format(record)
   8.621 +                self._welu.ReportEvent(self.appname, id, cat, type, [msg])
   8.622 +            except:
   8.623 +                self.handleError(record)
   8.624 +
   8.625 +    def close(self):
   8.626 +        """
   8.627 +        Clean up this handler.
   8.628 +
   8.629 +        You can remove the application name from the registry as a
   8.630 +        source of event log entries. However, if you do this, you will
   8.631 +        not be able to see the events as you intended in the Event Log
   8.632 +        Viewer - it needs to be able to access the registry to get the
   8.633 +        DLL name.
   8.634 +        """
   8.635 +        #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype)
   8.636 +        logging.Handler.close(self)
   8.637 +
   8.638 +class HTTPHandler(logging.Handler):
   8.639 +    """
   8.640 +    A class which sends records to a Web server, using either GET or
   8.641 +    POST semantics.
   8.642 +    """
   8.643 +    def __init__(self, host, url, method="GET"):
   8.644 +        """
   8.645 +        Initialize the instance with the host, the request URL, and the method
   8.646 +        ("GET" or "POST")
   8.647 +        """
   8.648 +        logging.Handler.__init__(self)
   8.649 +        method = string.upper(method)
   8.650 +        if method not in ["GET", "POST"]:
   8.651 +            raise ValueError, "method must be GET or POST"
   8.652 +        self.host = host
   8.653 +        self.url = url
   8.654 +        self.method = method
   8.655 +
   8.656 +    def mapLogRecord(self, record):
   8.657 +        """
   8.658 +        Default implementation of mapping the log record into a dict
   8.659 +        that is sent as the CGI data. Overwrite in your class.
   8.660 +        Contributed by Franz  Glasner.
   8.661 +        """
   8.662 +        return record.__dict__
   8.663 +
   8.664 +    def emit(self, record):
   8.665 +        """
   8.666 +        Emit a record.
   8.667 +
   8.668 +        Send the record to the Web server as an URL-encoded dictionary
   8.669 +        """
   8.670 +        try:
   8.671 +            import httplib, urllib
   8.672 +            h = httplib.HTTP(self.host)
   8.673 +            url = self.url
   8.674 +            data = urllib.urlencode(self.mapLogRecord(record))
   8.675 +            if self.method == "GET":
   8.676 +                if (string.find(url, '?') >= 0):
   8.677 +                    sep = '&'
   8.678 +                else:
   8.679 +                    sep = '?'
   8.680 +                url = url + "%c%s" % (sep, data)
   8.681 +            h.putrequest(self.method, url)
   8.682 +            if self.method == "POST":
   8.683 +                h.putheader("Content-length", str(len(data)))
   8.684 +            h.endheaders()
   8.685 +            if self.method == "POST":
   8.686 +                h.send(data)
   8.687 +            h.getreply()    #can't do anything with the result
   8.688 +        except:
   8.689 +            self.handleError(record)
   8.690 +
   8.691 +class BufferingHandler(logging.Handler):
   8.692 +    """
   8.693 +  A handler class which buffers logging records in memory. Whenever each
   8.694 +  record is added to the buffer, a check is made to see if the buffer should
   8.695 +  be flushed. If it should, then flush() is expected to do what's needed.
   8.696 +    """
   8.697 +    def __init__(self, capacity):
   8.698 +        """
   8.699 +        Initialize the handler with the buffer size.
   8.700 +        """
   8.701 +        logging.Handler.__init__(self)
   8.702 +        self.capacity = capacity
   8.703 +        self.buffer = []
   8.704 +
   8.705 +    def shouldFlush(self, record):
   8.706 +        """
   8.707 +        Should the handler flush its buffer?
   8.708 +
   8.709 +        Returns true if the buffer is up to capacity. This method can be
   8.710 +        overridden to implement custom flushing strategies.
   8.711 +        """
   8.712 +        return (len(self.buffer) >= self.capacity)
   8.713 +
   8.714 +    def emit(self, record):
   8.715 +        """
   8.716 +        Emit a record.
   8.717 +
   8.718 +        Append the record. If shouldFlush() tells us to, call flush() to process
   8.719 +        the buffer.
   8.720 +        """
   8.721 +        self.buffer.append(record)
   8.722 +        if self.shouldFlush(record):
   8.723 +            self.flush()
   8.724 +
   8.725 +    def flush(self):
   8.726 +        """
   8.727 +        Override to implement custom flushing behaviour.
   8.728 +
   8.729 +        This version just zaps the buffer to empty.
   8.730 +        """
   8.731 +        self.buffer = []
   8.732 +
   8.733 +    def close(self):
   8.734 +        """
   8.735 +        Close the handler.
   8.736 +
   8.737 +        This version just flushes and chains to the parent class' close().
   8.738 +        """
   8.739 +        self.flush()
   8.740 +        logging.Handler.close(self)
   8.741 +
   8.742 +class MemoryHandler(BufferingHandler):
   8.743 +    """
   8.744 +    A handler class which buffers logging records in memory, periodically
   8.745 +    flushing them to a target handler. Flushing occurs whenever the buffer
   8.746 +    is full, or when an event of a certain severity or greater is seen.
   8.747 +    """
   8.748 +    def __init__(self, capacity, flushLevel=logging.ERROR, target=None):
   8.749 +        """
   8.750 +        Initialize the handler with the buffer size, the level at which
   8.751 +        flushing should occur and an optional target.
   8.752 +
   8.753 +        Note that without a target being set either here or via setTarget(),
   8.754 +        a MemoryHandler is no use to anyone!
   8.755 +        """
   8.756 +        BufferingHandler.__init__(self, capacity)
   8.757 +        self.flushLevel = flushLevel
   8.758 +        self.target = target
   8.759 +
   8.760 +    def shouldFlush(self, record):
   8.761 +        """
   8.762 +        Check for buffer full or a record at the flushLevel or higher.
   8.763 +        """
   8.764 +        return (len(self.buffer) >= self.capacity) or \
   8.765 +                (record.levelno >= self.flushLevel)
   8.766 +
   8.767 +    def setTarget(self, target):
   8.768 +        """
   8.769 +        Set the target handler for this handler.
   8.770 +        """
   8.771 +        self.target = target
   8.772 +
   8.773 +    def flush(self):
   8.774 +        """
   8.775 +        For a MemoryHandler, flushing means just sending the buffered
   8.776 +        records to the target, if there is one. Override if you want
   8.777 +        different behaviour.
   8.778 +        """
   8.779 +        if self.target:
   8.780 +            for record in self.buffer:
   8.781 +                self.target.handle(record)
   8.782 +            self.buffer = []
   8.783 +
   8.784 +    def close(self):
   8.785 +        """
   8.786 +        Flush, set the target to None and lose the buffer.
   8.787 +        """
   8.788 +        self.flush()
   8.789 +        self.target = None
   8.790 +        BufferingHandler.close(self)
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/tools/python/logging/logging-0.4.9.2/python_logging.html	Thu Jul 22 13:42:39 2004 +0000
     9.3 @@ -0,0 +1,1183 @@
     9.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
     9.5 +"http://www.w3.org/TR/REC-html40/loose.dtd">
     9.6 +<html>
     9.7 +
     9.8 +<head>
     9.9 +<meta name="AUTHOR" content="Vinay Sajip">
    9.10 +<meta name="COPYRIGHT" content="© 2002 Red Dove Consultants Limited">
    9.11 +<meta name="KEYWORDS" content="Red Dove Consultants, Python, logging, PEP 282">
    9.12 +<meta name="DESCRIPTION" content="A logging system for Python">
    9.13 +<meta name="summary" content="A logging system for Python">
    9.14 +<meta name="publisher" content="Red Dove Consultants Limited">
    9.15 +<meta name="identifier" content="http://www.red-dove.com">
    9.16 +<title>A Logging System for Python</title>
    9.17 +<link title="Default Style" rel="stylesheet" href="default.css" type="text/css">
    9.18 +</head>
    9.19 +
    9.20 +<body style="margin: 5px" marginheight="0">
    9.21 +<table border="0" width="100%" cellspacing="0" cellpadding="0">
    9.22 +  <tr>
    9.23 +    <td class="bigtd">A Logging System for Python</td>
    9.24 +    <td rowspan="2" align="right" style="text-align: right; vertical-align: top"><a href="/index.html">Home</a><br>
    9.25 +    <a href="#download">Download</a><br>
    9.26 +    <a href="#license">Copyright &amp; License</a><br>
    9.27 +    <a href="#changes">Recent Changes</a><br>
    9.28 +    <!-- a href="logging_manual.html">Online Manual</a --></td>
    9.29 +  </tr>
    9.30 +  <tr>
    9.31 +  <td>"Oh, I'm a lumberjack and I'm okay..." <small>(Monty Python, <a href="http://www.montypython.net/scripts/lumberj.php">The Lumberjack Song</a>)</small></td>
    9.32 +  </tr>
    9.33 +</table>
    9.34 +
    9.35 +<h4>Table of Contents</h4>
    9.36 +<a href="#abstract">Abstract</a><br>
    9.37 +<a href="#motivation">Motivation</a><br>
    9.38 +<a href="#influences">Influences</a><br>
    9.39 +<a href="#simplest">A Simple Example</a><br>
    9.40 +<a href="#ctrlflow">Control Flow</a><br>
    9.41 +<a href="#levels">Levels</a><br>
    9.42 +<a href="#loggers">Loggers</a><br>
    9.43 +<a href="#handlers">Handlers</a><br>
    9.44 +<a href="#formatters">Formatters</a><br>
    9.45 +<a href="#filters">Filters</a><br>
    9.46 +<a href="#config">Configuration</a><br>
    9.47 +<a href="#guiconf">The GUI Configurator</a><br>
    9.48 +<a href="#scenarios">Case Scenarios</a><br>
    9.49 +<a href="#threadsafe">Thread Safety</a><br>
    9.50 +<a href="#onthefly">On-The-Fly Reconfiguration</a><br>
    9.51 +<a href="#mlcf">Module-Level Convenience Functions</a><br>
    9.52 +<a href="#perf">Performance</a><br>
    9.53 +<a href="#impstatus">Implementation Status</a><br>
    9.54 +<a href="#acks">Acknowledgements</a><br>
    9.55 +<a href="#todo">Still To Do</a><br>
    9.56 +<a href="#download">Download and Installation</a><br>
    9.57 +<a href="#changes">Change History</a><br>
    9.58 +<a href="#license">Copyright and License</a><br>
    9.59 +
    9.60 +<a name="abstract"></a><h4>Abstract</h4>
    9.61 +
    9.62 +<p>There is a need for a standard logging system in Python, as comprehensively documented
    9.63 +in <a href="http://www.python.org/peps/pep-0282.html">PEP 282</a> and
    9.64 +enthusiastically endorsed by the BDFL in the <a
    9.65 +href="http://www.python.org/doc/essays/pepparade.html">Parade of the PEPs</a>. By a happy
    9.66 +coincidence, the package described here was already in development and fairly close in
    9.67 +intent and design to the description in the aforementioned PEP, borrowing as it did
    9.68 +heavily from JSR-47 (now JDK 1.4's java.util.logging package) and <a
    9.69 +href="http://jakarta.apache.org/log4j/">log4j</a>. This page describes it in more detail.
    9.70 +As I have tweaked the package to meet comments on PEP 282, I have structured this page in
    9.71 +the same way as the original PEP. </p>
    9.72 +
    9.73 +<a name="motivation"></a><h4>Motivation</h4>
    9.74 +
    9.75 +<p>The Python community has been incredibly helpful to me, a relative newcomer to the
    9.76 +language. Python and its community has certainly saved me much time and effort, and it
    9.77 +seems appropriate to give something back to the community by offering up this package for
    9.78 +people to try. Any <a href="mailto:vinay_sajip@red-dove.com">feedback</a> will be gratefully accepted. </p>
    9.79 +
    9.80 +<a name="influences"></a><h4>Influences</h4>
    9.81 +
    9.82 +<p>This package owes its greatest debt to Apache <a
    9.83 +href="http://jakarta.apache.org/log4j/">log4j</a>. Due notice was also taken of log4j's
    9.84 +comprehensive <a href="http://jakarta.apache.org/log4j/docs/critique.html">critique</a> of
    9.85 +JSR47. This package bears a close resemblance to log4j, but is not a close translation
    9.86 +(as, for example, <a href="http://log4p.sourceforge.net/">log4p</a> appears to be). I have
    9.87 +attempted to be more minimalist (and hopefully more Pythonic) in my approach. You be the
    9.88 +judge! </p>
    9.89 +
    9.90 +<a name="simplest"></a><h4>A Simple Example</h4>
    9.91 +
    9.92 +<p>Using the package doesn't get much simpler. It is packaged as a standard Python package called (unsurprisingly) <code>logging</code>. You just need to <code>import logging</code> and you're ready to go. Minimal example: </p>
    9.93 +
    9.94 +<pre class="program">
    9.95 +# --- app.py --------------------------------------------------------------------
    9.96 +import logging
    9.97 +
    9.98 +logging.warn(&quot;Hello&quot;)
    9.99 +logging.error(&quot;Still here...&quot;)
   9.100 +logging.warn(&quot;Goodbye&quot;)
   9.101 +</pre>
   9.102 +
   9.103 +<p>When you run <code>app.py</code>, the results are: </p>
   9.104 +
   9.105 +<pre class="output">
   9.106 +WARN:root:Hello
   9.107 +ERROR:root:Still here...
   9.108 +WARN:root:Goodbye
   9.109 +</pre>
   9.110 +
   9.111 +<p>Don't worry about the format of the output - it's all configurable. Here's a slightly
   9.112 +more involved example; if you've just looked at PEP 282 you will probably get a feeling of
   9.113 +dejà vu. (This is intentional.)</p>
   9.114 +
   9.115 +<a name="nextsimplest"></a><pre class="program">
   9.116 +# --- mymodule.py --------------------------------------------------------------------
   9.117 +import logging
   9.118 +log = logging.getLogger(&quot;MyModule&quot;)
   9.119 +
   9.120 +def doIt():
   9.121 +    log.debug(&quot;doin' stuff&quot;)
   9.122 +    <span class="comment">#do stuff...but suppose an error occurs?</span>
   9.123 +    raise TypeError, &quot;bogus type error for testing&quot;
   9.124 +
   9.125 +# --- myapp.py -----------------------------------------------------------------------
   9.126 +import logging, mymodule
   9.127 +
   9.128 +logging.basicConfig()
   9.129 +
   9.130 +log = logging.getLogger(&quot;MyApp&quot;)
   9.131 +log.setLevel(logging.DEBUG) <span class="comment">#set verbosity to show all messages of severity >= DEBUG</span>
   9.132 +log.info(&quot;Starting my app&quot;)
   9.133 +try:
   9.134 +    mymodule.doIt()
   9.135 +except Exception, e:
   9.136 +    log.exception(&quot;There was a problem.&quot;)
   9.137 +log.info(&quot;Ending my app&quot;)
   9.138 +</pre>
   9.139 +
   9.140 +<p>When you run <code>myapp.py</code>, the results are: </p>
   9.141 +
   9.142 +<pre class="output">
   9.143 +INFO:MyApp:Starting my app
   9.144 +ERROR:MyApp:There was a problem.
   9.145 +Traceback (most recent call last):
   9.146 +  File "myapp.py", line 9, in ?
   9.147 +    mymodule.doIt()
   9.148 +  File "mymodule.py", line 7, in doIt
   9.149 +    raise TypeError, "Bogus type error for testing"
   9.150 +TypeError: Bogus type error for testing
   9.151 +INFO:MyApp:Ending my app
   9.152 +</pre>
   9.153 +
   9.154 +<p>But don't worry - the above output is not hardcoded into the package. It's just an
   9.155 +example of what you can do with very little work. As you can see, exceptions are handled
   9.156 +as one would expect. </p>
   9.157 +
   9.158 +<a name="ctrlflow"></a><h4>Control Flow</h4>
   9.159 +
   9.160 +<p>The package pretty much matches the PEP regarding control flow. The user of the package
   9.161 +makes logging calls on instances of <code>Logger</code>, which are organized into a
   9.162 +hierarchy based on a &quot;dotted name&quot; namespace. This hierarchy is embodied in an
   9.163 +encapsulated singleton <code>Manager</code> instance (which can be ignored by users of the
   9.164 +package, for most purposes). Based on the type of logging call and the logging
   9.165 +configuration (see below), the call may be passed through a set of <code>Filter</code>
   9.166 +instances to decide whether it should be dropped. If not, then the logger consults a set
   9.167 +of <code>Handler</code> instances which are associated with it, and asks each handler
   9.168 +instance to &quot;handle&quot; the logging event. By default, the system moves up the
   9.169 +namespace hierarchy and invokes handlers on all loggers at or above the level of the
   9.170 +logger on which the logging call was made. (You can override this by setting a logger's
   9.171 +&quot;propagate&quot; attribute to 0 - no traversal up the hierarchy is made from such a
   9.172 +logger. But I'm getting ahead of myself...) </p>
   9.173 +
   9.174 +<p>Handlers are passed <code>LogRecord</code> instances which (should) contain all the
   9.175 +information we're interested in logging. Handlers, too, can invoke filters to determine
   9.176 +whether a record should be dropped. If not, then the handler takes a handler-specific
   9.177 +action to actually log the record to a file, the console or whatever.</p>
   9.178 +
   9.179 +<a name="levels"></a><h4>Levels</h4>
   9.180 +
   9.181 +<p>The following levels are implemented by default: </p>
   9.182 +
   9.183 +<pre>
   9.184 +DEBUG
   9.185 +INFO
   9.186 +WARN
   9.187 +ERROR
   9.188 +CRITICAL
   9.189 +</pre>
   9.190 +
   9.191 +<p>The <code>CRITICAL</code> level replaces the earlier <code>FATAL</code> level. You can use either (for now), but <code>CRITICAL</code> is preferred since <code>FATAL</code> implies that the application is about to terminate. This is not true for many systems which use logging - for example, a Web server application which encounters a <code>CRITICAL</code> condition (e.g. running out of resources) will still try to keep going as best it can.</p>
   9.192 +<p><code>FATAL</code> (and the corresponding <code>fatal()</code> methods) may be removed in future versions of the package. Currently, <code>CRITICAL</code> is synonymous with <code>FATAL</code> and <code>critical()</code> methods are synonymous with <code>fatal()</code>.</p>
   9.193 +<p>Exceptions logged via <code>exception()</code> use the <code>ERROR</code> level for logging. If it is desired to log exception information with arbitrary logging levels, this can be done by passing a keyword argument <code>exc_info</code> with a true value to the logging methods (see the pydoc for more details).</p>
   9.194 +<p>The levels are not deeply hardcoded into the package - the number of levels, their numeric values and their textual representation are all configurable. The above levels represent the experience of the log4j community and so are provided as the default levels for users who do not have very specific requirements in this area.</p>
   9.195 +<p>The example script <code>log_test4.py</code> shows the use of bespoke logging levels (as well as filtering by level at logger and handler, as well as use of filter classes).</p>
   9.196 +
   9.197 +<a name="loggers"></a><h4>Loggers</h4>
   9.198 +
   9.199 +<p>The package implements loggers pretty much as mentioned in the PEP, except that the manager class is called <code>Manager</code> rather than <code>LogManager</code>.</p>
   9.200 +<p>Each Logger instance represents "an area" of the application. This somewhat nebulous definition is needed because it's entirely up to each application developer to define an application's "areas".</p><p>For example, an application which reads and processes spreadsheet-type data in different formats might have an overall area "input", concerned with reading input files; and areas "input.csv", "input.xls" and "input.gnu", related to processing comma-separated-value, Excel and Gnumeric input files. Logging messages relating to the overall input function (e.g. deciding which files to process) might be logged used the logger named "input"; logging messages relating to reading individual files might be sent to any of "input.csv", "input.xls" or "input.gnu" depending on the type of file being read.</p><p>The advantage of the hierarchical structure is that logging verbosity may be controlled either at the high level or the low level. The levels are loosely coupled and new levels can easily be added at a later date, e.g."input.wks" for reading Lotus-123 format files. It's also possible to do things like routing messages relating to Excel file input to whoever is working on Excel imports, messages related to Gnumeric file processing to a different developer, and so on. Even if the same person works on both, they can at different times focus logging verbosity on particular areas of interest - for example, when debugging Excel imports, they can set the "input.xls" logger's verbosity to DEBUG and others to CRITICAL, and when moving to debug Gnumeric imports, they can reduce the "input.xls" verbosity by setting the level to CRITICAL, while increasing "input.gnu"'s verbosity by setting the level to DEBUG.</p>
   9.201 +
   9.202 +<a name="handlers"></a><h4>Handlers</h4>
   9.203 +
   9.204 +<p>The following handlers are implemented. I guess they could use more testing ;-)
   9.205 +
   9.206 +<ul>
   9.207 +  <li>StreamHandler - logging to a stream, defaulting to sys.stderr.</li>
   9.208 +  <li>FileHandler - logging to disk files.</li>
   9.209 +  <li>RotatingFileHandler - logging to disk files with support for rollover, rotating files.</li>
   9.210 +  <li>SocketHandler - logging to a streaming socket.</li>
   9.211 +  <li>DatagramHandler - logging to a UDP socket.</li>
   9.212 +  <li>SMTPHandler - logging to an email address.</li>
   9.213 +  <li>SysLogHandler - logging to Unix syslog. Contributed by Nicolas Untz, based on <a href="http://www.nightmare.com/squirl/python-ext/misc/syslog.py
   9.214 +">Sam Rushing's syslog module</a>.</li>
   9.215 +  <li>MemoryHandler - buffering records in memory until a specific trigger occurs (or until the buffer gets full).</li>
   9.216 +  <li>NTEventLogHandler - writes events to the NT event log. For this to work, you need to have Mark Hammond's Win32 extensions installed. (Though of course you can still log to NT from other platforms - just use SocketHandler to redirect to an NT machine).</li>
   9.217 +  <li>HTTPHandler - sends events to a Web server using either GET or POST semantics.</li>
   9.218 +</ul>
   9.219 +<p>All of these except the first two are defined in a sub-module, handlers.py. (To use these handlers, you'll need to <code>import logging.handlers</code>. In addition to the above list, there are example implementations of <code>XMLHandler</code> (see <code>log_test9.py</code>), <code>BufferingSMTPHandler</code> (see <code>log_test11.py</code>) and <code>DBHandler</code> (see <code>log_test14.py</code>) in the test harnesses, on which you can base more specific classes. There is also a class called <code>SLHandler</code> (see <code>log_test1.py</code>) which implements an alternative SysLogHandler - one which uses the syslog module in the standard library (and which is therefore only available on Unix).</p>
   9.220 +<p>SOAPHandler, which sends events to a SOAP server, has moved (as of release 0.4.4) from the core to an example script (log_test13.py). The SOAP message is packaged as a function call to a single <code>log()</code> function on the remote server, which takes each relevant member of the  LogRecord as a positional parameter. This is perhaps not ideal - but then this SOAPHandler is just a proof-of-concept example to get you started ;-)</p>
   9.221 +<p>Note that the handlers are specifically intended <I>not</I> to raise exceptions when errors occur at runtime. This is to avoid error messages from the logging infrastructure polluting logging messages from the application being logged. If, for example, a SocketHandler sees a connection reset by the remote endpoint, it will silently drop all records passed to it (but it will try to connect each time). It may be that due to bugs there are some exceptions incorrectly raised by the logging system, I will try to rectify this kind of problem as soon as it is found and reported!</p>
   9.222 +
   9.223 +<a name="formatters"></a><h4>Formatters</h4>
   9.224 +
   9.225 +<p>A basic Formatter has been implemented, which should cater for most immediate
   9.226 +requirements. You basically initialize the Formatter with a format string which knows how the attribute dictionary of a LogRecord looks. For example, the output in the example above was produced
   9.227 +with a format string of <code>&quot;%(asctime)s %(name)-19s %(levelname)-5s -
   9.228 +%(message)s&quot;</code>. Note that the &quot;message&quot; attribute of the <code>LogRecord</code>
   9.229 +is derived from <code>&quot;msg % args&quot;</code> where <code>msg</code> and <code>args</code>
   9.230 +are passed by the the user in a logging call.</p>
   9.231 +
   9.232 +<a name="filters"></a><h4>Filters</h4>
   9.233 +
   9.234 +<p>Filters are used to refine logging output at either logger or handler level with a finer control than is available by just using logging levels. The basic Filter class takes an optional name argument and passes all logging records from loggers which are at or below the specified name.</p>
   9.235 +<p>For example, a <code>Filter</code> initialized with "A.B" will allow events logged by loggers "A.B", "A.B.C", "A.B.C.D", "A.B.D" but not "A.BB", "B.A.B".  If no name is specified, all events are passed by the filter.</p>
   9.236 +
   9.237 +<a name="config"></a><h4>Configuration</h4>
   9.238 +
   9.239 +<p>A basic configuration is provided via a module-level function, <code>basicConfig()</code>.
   9.240 +If you want to use very simple logging, you can just call the <a href="#mlcf">module-level
   9.241 +convenience functions</a> and they will call <code>basicConfig()</code> for you if
   9.242 +necessary. It (basically) adds a <code>StreamHandler</code> (which writes to <code>sys.stderr</code>)to the root <code>Logger</code>.</p>
   9.243 +
   9.244 +<p>There are numerous examples of configuration in the test/example scripts included in the distribution. For example, <code>log_test8.py</code> has an example of using a file-based logger.</p>
   9.245 +<p>An alternative using ConfigParser-based configuration files is also available (the older, dict-based function is no more). To use this functionality, you'll need to <code>import logging.config</code>. Here is an example of such a config file - it's a bit long, but a full working example so bear with me. I've annotated it as best I can :-): </p>
   9.246 +<p>
   9.247 +In the listing below, some values are used by both the logging configuration API
   9.248 +and the GUI configurator, while others are used only by the GUI configurator. To
   9.249 +make it clearer which values you absolutely need to have in the .ini file for it to be useful even if you hand-code it, the values used by the configuration API are shown
   9.250 +<span class="program"><span class="strong">like this</span></span>. (The other ones are used by the GUI configurator, but ignored by the configuration API.)
   9.251 +</p>
   9.252 +<pre class="program">
   9.253 +# --- logconf.ini -----------------------------------------------------------
   9.254 +#The "loggers" section contains the key names for all the loggers in this
   9.255 +#configuration. These are not the actual channel names, but values used to
   9.256 +#identify where the parameters for each logger are found in this file.
   9.257 +#The section for an individual logger is named "logger_xxx" where the "key"
   9.258 +#for a logger is "xxx". So ... "logger_root", "logger_log02", etc. further
   9.259 +#down the file, indicate how the root logger is set up, logger "log_02" is set
   9.260 +#up, and so on.
   9.261 +#Logger key names can be any identifier, except "root" which is reserved for
   9.262 +#the root logger. (The names "lognn" are generated by the GUI configurator.)
   9.263 +
   9.264 +<span class="strong">[loggers]
   9.265 +keys=root,log02,log03,log04,log05,log06,log07</span>
   9.266 +
   9.267 +#The "handlers" section contains the key names for all the handlers in this
   9.268 +#configuration. Just as for loggers above, the key names are values used to
   9.269 +#identify where the parameters for each handler are found in this file.
   9.270 +#The section for an individual handler is named "handler_xxx" where the "key"
   9.271 +#for a handler is "xxx". So sections "handler_hand01", "handler_hand02", etc.
   9.272 +#further down the file, indicate how the handlers "hand01", "hand02" etc.
   9.273 +#are set up.
   9.274 +#Handler key names can be any identifier. (The names "handnn" are generated
   9.275 +#by the GUI configurator.)
   9.276 +
   9.277 +<span class="strong">[handlers]
   9.278 +keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09</span>
   9.279 +
   9.280 +#The "formatters" section contains the key names for all the formatters in
   9.281 +#this configuration. Just as for loggers and handlers above, the key names
   9.282 +#are values used to identify where the parameters for each formatter are found
   9.283 +#in this file.
   9.284 +#The section for an individual formatter is named "formatter_xxx" where the
   9.285 +#"key" for a formatter is "xxx". So sections "formatter_form01",
   9.286 +#"formatter_form02", etc. further down the file indicate how the formatters
   9.287 +#"form01", "form02" etc. are set up.
   9.288 +#Formatter key names can be any identifier. (The names "formnn" are generated
   9.289 +#by the GUI configurator.)
   9.290 +
   9.291 +<span class="strong">[formatters]
   9.292 +keys=form01,form02,form03,form04,form05,form06,form07,form08,form09</span>
   9.293 +
   9.294 +#The section below indicates the information relating to the root logger.
   9.295 +#
   9.296 +#The level value needs to be one of DEBUG, INFO, WARN, ERROR, CRITICAL or NOTSET.
   9.297 +#In the root logger, NOTSET indicates that all messages will be logged.
   9.298 +#Level values are eval()'d in the context of the logging package's namespace.
   9.299 +#
   9.300 +#The propagate value indicates whether or not parents of this loggers will
   9.301 +#be traversed when looking for handlers. It doesn't really make sense in the
   9.302 +#root logger - it's just there because a root logger is almost like any other
   9.303 +#logger.
   9.304 +#
   9.305 +#The channel value indicates the lowest portion of the channel name of the
   9.306 +#logger. For a logger called "a.b.c", this value would be "c".
   9.307 +#
   9.308 +#The parent value indicates the key name of the parent logger, except that
   9.309 +#root is shown as "(root)" rather than "root".
   9.310 +#
   9.311 +#The qualname value is the fully qualified channel name of the logger. For a
   9.312 +#logger called "a.b.c", this value would be "a.b.c".
   9.313 +#
   9.314 +#The handlers value is a comma-separated list of the key names of the handlers
   9.315 +#attached to this logger.
   9.316 +#
   9.317 +<span class="strong">[logger_root]
   9.318 +level=NOTSET
   9.319 +handlers=hand01</span>
   9.320 +qualname=(root) <span class="comment"># note - this is used in non-root loggers</span>
   9.321 +propagate=1 <span class="comment"># note - this is used in non-root loggers</span>
   9.322 +channel=
   9.323 +parent=
   9.324 +
   9.325 +#
   9.326 +#The explanation for the values in this section is analogous to the above. The
   9.327 +#logger is named "log02" and coincidentally has a key name of "log02". It has
   9.328 +#a level of DEBUG and handler with key name "hand02". (See section
   9.329 +#"handler_hand02" for handler details.) If the level value were NOTSET, this tells
   9.330 +#the logging package to consult the parent (as long as propagate is 1) for the
   9.331 +#effective level of this logger. If propagate is 0, this level is treated as for
   9.332 +#the root logger - a value of NOTSET means "pass everything", and other values are
   9.333 +#interpreted at face value.
   9.334 +#
   9.335 +<span class="strong">[logger_log02]
   9.336 +level=DEBUG
   9.337 +propagate=1
   9.338 +qualname=log02
   9.339 +handlers=hand02</span>
   9.340 +channel=log02
   9.341 +parent=(root)
   9.342 +
   9.343 +#
   9.344 +#The explanation for the values in this section is analogous to the above. The
   9.345 +#logger is named "log02.log03" and has a key name of "log03".
   9.346 +#It has a level of INFO and handler with key name "hand03".
   9.347 +#
   9.348 +<span class="strong">[logger_log03]
   9.349 +level=INFO
   9.350 +propagate=1
   9.351 +qualname=log02.log03
   9.352 +handlers=hand03</span>
   9.353 +channel=log03
   9.354 +parent=log02
   9.355 +
   9.356 +#
   9.357 +#The explanations for the values in this section and subsequent logger sections
   9.358 +#are analogous to the above.
   9.359 +#
   9.360 +<span class="strong">[logger_log04]
   9.361 +level=WARN
   9.362 +propagate=0
   9.363 +qualname=log02.log03.log04
   9.364 +handlers=hand04</span>
   9.365 +channel=log04
   9.366 +parent=log03
   9.367 +
   9.368 +<span class="strong">[logger_log05]
   9.369 +level=ERROR
   9.370 +propagate=1
   9.371 +qualname=log02.log03.log04.log05
   9.372 +handlers=hand05</span>
   9.373 +channel=log05
   9.374 +parent=log04
   9.375 +
   9.376 +<span class="strong">[logger_log06]
   9.377 +level=CRITICAL
   9.378 +propagate=1
   9.379 +qualname=log02.log03.log04.log05.log06
   9.380 +handlers=hand06</span>
   9.381 +channel=log06
   9.382 +parent=log05
   9.383 +
   9.384 +<span class="strong">[logger_log07]
   9.385 +level=WARN
   9.386 +propagate=1
   9.387 +qualname=log02.log03.log04.log05.log06.log07
   9.388 +handlers=hand07</span>
   9.389 +channel=log07
   9.390 +parent=log06
   9.391 +
   9.392 +#The section below indicates the information relating to handler "hand01".
   9.393 +#The first three keys (class, level and formatter) are common to all handlers.
   9.394 +#Any other values are handler-specific, except that "args", when eval()'ed,
   9.395 +#is the list of arguments to the constructor for the handler class.
   9.396 +#
   9.397 +#The class value indicates the handler's class (as determined by eval() in
   9.398 +#the logging package's namespace).
   9.399 +#
   9.400 +#The level value needs to be one of DEBUG, INFO, WARN, ERROR, CRITICAL or NOTSET.
   9.401 +#NOTSET means "use the parent's level".
   9.402 +#
   9.403 +#The formatter value indicates the key name of the formatter for this handler.
   9.404 +#If blank, a default formatter (logging._defaultFormatter) is used.
   9.405 +#
   9.406 +#The stream value indicates the stream for this StreamHandler. It is computed
   9.407 +#by doing eval() on the string value in the context of the logging package's
   9.408 +#namespace.
   9.409 +#
   9.410 +#The args value is a tuple of arguments which is passed to the constructor for
   9.411 +#this handler's class in addition to the "self" argument.
   9.412 +#
   9.413 +<span class="strong">[handler_hand01]
   9.414 +class=StreamHandler
   9.415 +level=NOTSET
   9.416 +formatter=form01
   9.417 +args=(sys.stdout,)</span>
   9.418 +stream=sys.stdout
   9.419 +
   9.420 +#The section below indicates the information relating to handler "hand02".
   9.421 +#The first three keys are common to all handlers.
   9.422 +#Any other values are handler-specific, except that "args", when eval()'ed,
   9.423 +#is the list of arguments to the constructor for the handler class.
   9.424 +#
   9.425 +#The filename value is the name of the file to write logging information to.
   9.426 +#The mode value is the mode used to open() the file. The maxsize and backcount
   9.427 +#values control rollover as described in the package's pydoc.
   9.428 +#
   9.429 +<span class="strong">[handler_hand02]
   9.430 +class=FileHandler
   9.431 +level=DEBUG
   9.432 +formatter=form02
   9.433 +args=('python.log', 'w')</span>
   9.434 +filename=python.log
   9.435 +mode=w
   9.436 +
   9.437 +#The section below indicates the information relating to handler "hand03".
   9.438 +#The first three keys are common to all handlers.
   9.439 +#Any other values are handler-specific, except that "args", when eval()'ed,
   9.440 +#is the list of arguments to the constructor for the handler class.
   9.441 +#
   9.442 +#The host value is the name of the host to send logging information to.
   9.443 +#The port value is the port number to use for the socket connection.
   9.444 +#
   9.445 +<span class="strong">[handler_hand03]
   9.446 +class=handlers.SocketHandler
   9.447 +level=INFO
   9.448 +formatter=form03
   9.449 +args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)</span>
   9.450 +host=localhost
   9.451 +port=DEFAULT_TCP_LOGGING_PORT
   9.452 +
   9.453 +#The section below indicates the information relating to handler "hand04".
   9.454 +#The first three keys are common to all handlers.
   9.455 +#Any other values are handler-specific, except that "args", when eval()'ed,
   9.456 +#is the list of arguments to the constructor for the handler class.
   9.457 +#
   9.458 +#The host value is the name of the host to send logging information to.
   9.459 +#The port value is the port number to use for the socket connection.
   9.460 +#
   9.461 +<span class="strong">[handler_hand04]
   9.462 +class=handlers.DatagramHandler
   9.463 +level=WARN
   9.464 +formatter=form04
   9.465 +args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)</span>
   9.466 +host=localhost
   9.467 +port=DEFAULT_UDP_LOGGING_PORT
   9.468 +
   9.469 +#The section below indicates the information relating to handler "hand05".
   9.470 +#The first three keys are common to all handlers.
   9.471 +#Any other values are handler-specific, except that "args", when eval()'ed,
   9.472 +#is the list of arguments to the constructor for the handler class.
   9.473 +#
   9.474 +#The host value is the name of the host to send logging information to.
   9.475 +#The port value is the port number to use for the socket connection.
   9.476 +#The facility is the syslog facility to use for logging.
   9.477 +#
   9.478 +<span class="strong">[handler_hand05]
   9.479 +class=handlers.SysLogHandler
   9.480 +level=ERROR
   9.481 +formatter=form05
   9.482 +args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)</span>
   9.483 +host=localhost
   9.484 +port=SYSLOG_UDP_PORT
   9.485 +facility=LOG_USER
   9.486 +
   9.487 +#The section below indicates the information relating to handler "hand06".
   9.488 +#The first three keys are common to all handlers.
   9.489 +#Any other values are handler-specific, except that "args", when eval()'ed,
   9.490 +#is the list of arguments to the constructor for the handler class.
   9.491 +#
   9.492 +#The appname value is the name of the application which appears in the
   9.493 +#NT event log.
   9.494 +#The dllname value is the pathname of a DLL to use for message definitions.
   9.495 +#The logtype is the type of NT event log to write to - Application, Security
   9.496 +#or System.
   9.497 +#
   9.498 +<span class="strong">[handler_hand06]
   9.499 +class=NTEventLogHandler
   9.500 +level=CRITICAL
   9.501 +formatter=form06
   9.502 +args=('Python Application', '', 'Application')</span>
   9.503 +appname=Python Application
   9.504 +dllname=
   9.505 +logtype=Application
   9.506 +
   9.507 +#The section below indicates the information relating to handler "hand07".
   9.508 +#The first three keys are common to all handlers.
   9.509 +#Any other values are handler-specific, except that "args", when eval()'ed,
   9.510 +#is the list of arguments to the constructor for the handler class.
   9.511 +#
   9.512 +#The host value is the name of the SMTP server to connect to.
   9.513 +#The port value is the port number to use for the SMTP connection.
   9.514 +#The from value is the "From" value in emails.
   9.515 +#The to value is a comma-separated list of email addresses.
   9.516 +#The subject value is the subject of the email.
   9.517 +#
   9.518 +<span class="strong">[handler_hand07]
   9.519 +class=SMTPHandler
   9.520 +level=WARN
   9.521 +formatter=form07
   9.522 +args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')</span>
   9.523 +host=localhost
   9.524 +port=25
   9.525 +from=from@abc
   9.526 +to=user1@abc,user2@xyz
   9.527 +subject=Logger Subject
   9.528 +
   9.529 +#The section below indicates the information relating to handler "hand08".
   9.530 +#The first three keys are common to all handlers.
   9.531 +#Any other values are handler-specific, except that "args", when eval()'ed,
   9.532 +#is the list of arguments to the constructor for the handler class.
   9.533 +#
   9.534 +#The capacity value is the size of this handler's buffer.
   9.535 +#The flushlevel value is the logging level at which the buffer is flushed.
   9.536 +#The from value is the "From" value in emails.
   9.537 +#The target value is the key name of the handler which messages are flushed
   9.538 +#to (i.e. sent to when flushing).
   9.539 +#
   9.540 +<span class="strong">[handler_hand08]
   9.541 +class=MemoryHandler
   9.542 +level=NOTSET
   9.543 +formatter=form08
   9.544 +target=
   9.545 +args=(10, ERROR)</span>
   9.546 +capacity=10
   9.547 +flushlevel=ERROR
   9.548 +
   9.549 +#The section below indicates the information relating to handler "hand09".
   9.550 +#The first three keys are common to all handlers.
   9.551 +#Any other values are handler-specific, except that "args", when eval()'ed,
   9.552 +#is the list of arguments to the constructor for the handler class.
   9.553 +#
   9.554 +#The host value is the name of the HTTP server to connect to.
   9.555 +#The port value is the port number to use for the HTTP connection.
   9.556 +#The url value is the url to request from the server.
   9.557 +#The method value is the HTTP request type (GET or POST).
   9.558 +#
   9.559 +<span class="strong">[handler_hand09]
   9.560 +class=HTTPHandler
   9.561 +level=NOTSET
   9.562 +formatter=form09
   9.563 +args=('localhost:9022', '/log', 'GET')</span>
   9.564 +host=localhost
   9.565 +port=9022
   9.566 +url=/log
   9.567 +method=GET
   9.568 +
   9.569 +#The sections below indicate the information relating to the various
   9.570 +#formatters. The format value is the overall format string, and the
   9.571 +#datefmt value is the strftime-compatible date/time format string. If
   9.572 +#empty, the logging package substitutes ISO8601 format date/times where
   9.573 +#needed. See the package pydoc for more details of the format string
   9.574 +#structure.
   9.575 +#
   9.576 +<span class="strong">[formatter_form01]
   9.577 +format=F1 %(asctime)s %(levelname)s %(message)s
   9.578 +datefmt=
   9.579 +
   9.580 +[formatter_form02]
   9.581 +format=F2 %(asctime)s %(pathname)s(%(lineno)d): %(levelname)s %(message)s
   9.582 +datefmt=
   9.583 +
   9.584 +[formatter_form03]
   9.585 +format=F3 %(asctime)s %(levelname)s %(message)s
   9.586 +datefmt=
   9.587 +
   9.588 +[formatter_form04]
   9.589 +format=%(asctime)s %(levelname)s %(message)s
   9.590 +datefmt=
   9.591 +
   9.592 +[formatter_form05]
   9.593 +format=F5 %(asctime)s %(levelname)s %(message)s
   9.594 +datefmt=
   9.595 +
   9.596 +[formatter_form06]
   9.597 +format=F6 %(asctime)s %(levelname)s %(message)s
   9.598 +datefmt=
   9.599 +
   9.600 +[formatter_form07]
   9.601 +format=F7 %(asctime)s %(levelname)s %(message)s
   9.602 +datefmt=
   9.603 +
   9.604 +[formatter_form08]
   9.605 +format=F8 %(asctime)s %(levelname)s %(message)s
   9.606 +datefmt=
   9.607 +
   9.608 +[formatter_form09]
   9.609 +format=F9 %(asctime)s %(levelname)s %(message)s
   9.610 +datefmt=</span>
   9.611 +
   9.612 +# --- end of logconf.ini ----------------------------------------------------
   9.613 +</pre>
   9.614 +
   9.615 +<p>To use a file like this, you would call <code>logging.config.fileConfig(&quot;logconf.ini&quot;)</code>
   9.616 +whereupon the file is read in and processed. Note that evaluation happens in the context of the logging package (hence the unqualified class names).
   9.617 +
   9.618 +
   9.619 +<a name="guiconf"></a><h4>The GUI Configurator</h4>
   9.620 +
   9.621 +To create a file like the above, you can use the new GUI configurator, <code>logconf.py</code>, which is invoked either with no arguments or with a single argument giving the name of a configuration file to read. (Or, if you're a masochist/don't have Tk, you can do it by hand. The configurator is a quick hack, which I hope is reasonably intuitive - have a play with it and see what you think. I've used it with 1.5.2 and 2.1.2 on Windows and 1.5.2 on Linux/x86. There's no validation, rudimentary error checking and the usability could be better, but it's something to build on, hey?)</p>
   9.622 +
   9.623 +<p>Here's a screenshot of the configurator:</p>
   9.624 +<img src="logconf.png" border="0"/>
   9.625 +<p>Here's a quick guide on how to use it:
   9.626 +<ul>
   9.627 +<li>The screen is laid out in three panels - for loggers, handlers and formatters (see the yellow rectangles in the screenshot).</li>
   9.628 +<li>Each panel consists of a listbox, New and Delete buttons and a "property editor" to set properties for each of the objects.</li>
   9.629 +<li>To create loggers, you need to first select the parent logger before clicking the New button. To create handlers and formatters, just click the appropriate New button.</li>
   9.630 +<li>To delete an item, just select it in the listbox and click the Delete button.</li>
   9.631 +<li>Whenever an item is selected in the listbox, its properties are displayed in the property editor section.</li>
   9.632 +<li>Whenever an item is deleted, the property editor section is cleared.</li>
   9.633 +<li>To edit a property, just click on the name or value. If the property is read-only, nothing happens. If it's a user-editable value, an entry field appears and you can type into it. If it's a user-selectable value (I mean selectable from a list), a button with ... appears. Clicking on it causes a pseudo-combobox to appear. All such boxes are single-selection, except for the "Handlers" property of loggers, for which several handlers can be selected.</li>
   9.634 +<li>To commit the changes, just click elsewhere in the property editor section, e.g. below the last property or on some other property.</li>
   9.635 +<li>Formatters are referred to by handlers, and handlers are referred to by loggers. Hence formatters and handlers have names generated for them automatically, for use in cross-referencing. The names of these cannot be changed. The name for loggers is, however, editable (except for the root logger), as it represents the position of the logger in the hierarchy.</li>
   9.636 +<li>The Load, Save, Save As and Reset buttons should be reasonably self-explanatory (except perhaps Reset, which just deletes all non-root loggers, handlers and formatters and starts with a clean slate).</li>
   9.637 +<li>Filters are not supported in this release, but will be as soon as time permits and if there is enough demand.</li>
   9.638 +</ul></p>
   9.639 +<a name="scenarios"></a><h4>Case Scenarios</h4>
   9.640 +
   9.641 +<p>With reference to the <a href="http://www.python.org/peps/pep-0282.html">PEP</a>,
   9.642 +here are my comments on the current state of play.
   9.643 +
   9.644 +<ol>
   9.645 +  <li>A short simple script. See the example <a href="#simplest"><code>app.py</code></a>
   9.646 +    above.</li>
   9.647 +  <li>Medium sized app with C extension module. I have not specifically considered C extension
   9.648 +    modules but I assume they can just use the standard Python C API to make logging calls.</li>
   9.649 +  <li>Distutils. I would welcome more specific comments on what kind of configuration people
   9.650 +    think would be useful. To a certain extent, controlling verbosity levels through setup.py
   9.651 +    options is, I think, the domain of the app developer rather than the logging package.</li>
   9.652 +  <li>Large applications. If users can restart a system after changing the logging settings
   9.653 +    (via some user-friendly or support-desk-friendly interface) then present functionality
   9.654 +    should cater for this. In the case where the logging behaviour of a (long-)running system needs
   9.655 +    to be changed, then the functionality (new in 0.4.3) described <a href="#onthefly">below</a> can be used.</li>
   9.656 +</ol>
   9.657 +
   9.658 +<a name="threadsafe"></a><h4>Thread Safety</h4>
   9.659 +
   9.660 +<p>The package is intended to be threadsafe. Although it makes no use of threads to provide its functionality (except for <a href="#onthefly">on-the-fly reconfiguration</a>), shared data in the package is protected by a thread lock which is acquired before, and released after, modifications to shared data. In addition, the Handler class creates a per-handler instance I/O lock which is acquired before, and released after, calling emit(). If you define your own handlers, in most situations you should not need to take any special precautions, as long as your I/O is called only from emit(). The thread locks impose a slight performance penalty, but it's no worse than for any other use of thread locks in Python applications.</p>
   9.661 +
   9.662 +<a name="onthefly"></a><h4>On-The-Fly Reconfiguration</h4>
   9.663 +
   9.664 +<p>The package also allows a program to permit changing of the logging configuration on the fly, i.e. <em>while the program is still running</em>. This should be a help for developers of long-running programs such as servers (e.g. Zope, Webware). At this stage, the on-the-fly configurability is fairly basic - to use it, two new module-level functions are provided (in the <code>logging.config</code> module).
   9.665 +<ul>
   9.666 +  <li><code>listen([port])</code> is used to create a thread which, when started, opens a socket server which listens on the specified port for configuration requests. The socket protocol is very basic - a two-byte length followed by a string of that length is sent to the listener. The string should be in the same format as logging configuration files, i.e. ConfigParser files conforming to the scheme described <a href="#config">above</a>.</li>
   9.667 +  <li><code>stopListening()</code> tells the thread created by listening to terminate.</li>
   9.668 +</ul>
   9.669 +Currently, you can't just change part of the logging configuration - the sent configuration completely replaces the existing configuration, and if previously existing loggers are not in the new configurations, they will be disabled after the new configuration takes effect. The script <code>log_test17.py</code> in the distribution illustrates the on-the-fly configuration feature.
   9.670 +</p>
   9.671 +
   9.672 +<a name="mlcf"></a><h4>Module-Level Convenience Functions</h4>
   9.673 +
   9.674 +<p>For the casual user, there are module-level convenience functions which operate on the
   9.675 +root logger. <a href="logging_pydoc.html#functions">Here</a> is the pydoc for them. </p>
   9.676 +
   9.677 +<a name="perf"></a><h4>Performance</h4>
   9.678 +
   9.679 +<p>The implementation has not been optimized for performance. This is planned to be done in a later phase, following feature stabilization and benchmarking.</p>
   9.680 +
   9.681 +<a name="impstatus"></a><h4>Implementation Status</h4>
   9.682 +
   9.683 +<p>The implementation is what I have termed alpha - mainly because it has not had very wide exposure or extensive testing in many environments. Please try to use it/break it and give me
   9.684 +any <a href="mailto:vinay_sajip@red-dove.com">feedback</a> you can! There is no reason I can see why this package should not be ready in time for the Python 2.3 release :-)</p>
   9.685 +
   9.686 +
   9.687 +<a name="#acks"></a><h4>Acknowledgements</h4>
   9.688 +<p>The biggest thank you goes to the <a href="http://jakarta.apache.org/log4j/">log4j</a> developers, whom I am attempting to flatter sincerely by imitation ;-) Thanks also to Trent Mick for <a href="http://www.python.org/peps/pep-0282.html">PEP 282</a>, which prompted me to offer this implementation.</p>
   9.689 +<p>I'd also like to thank all of the people who have given me feedback, patches and encouragement. In particular (but in no particular order):</p>
   9.690 +<ul>
   9.691 +<li>Ollie Rutherfurd - patches and suggestions.</li>
   9.692 +<li>Greg Ward - for nudging me in the direction of distutils.</li>
   9.693 +<li>Hunter Matthews - questions about user-defined logging levels.</li>
   9.694 +<li>Nicolas Untz - SysLogHandler implementation.</li>
   9.695 +<li>Jeremy Hylton - discussions about logging exceptions.</li>
   9.696 +<li>Kevin Butler - discussions about logging exceptions.</li>
   9.697 +<li>Richard Jones - lots of positive feedback and ideas.</li>
   9.698 +<li>David Goodger - suggestion about using CRITICAL rather than FATAL.</li>
   9.699 +<li>Denis S. Otkidach - suggestions on filters and feedback on performance.</li>
   9.700 +</ul>
   9.701 +<a name="todo"></a><h4>Still To Do</h4>
   9.702 +<p>No rest for the wicked...</p>
   9.703 +<ul>
   9.704 +<li>Improvements to the GUI configurator. Feedback, anyone?</li>
   9.705 +<li>Overview-type documentation? The pydoc is reasonably comprehensive (I like to think). Perhaps a slightly formalized version of the information on this page?</li>
   9.706 +<li>Testing, and more testing (you could help with this, too ...)</li>
   9.707 +</ul>
   9.708 +<p>If you can help with any of this, please <a href="mailto:vinay_sajip@red-dove.com">email me</a>.</p>
   9.709 +<a name="download"></a><h4>Download and Installation</h4>
   9.710 +<p>The current version is 0.4.7. <a href="logging-0.4.7.tar.gz">Here</a> is the latest tarball (also in <a href="logging-0.4.7.zip">zip</a> format or <a href="logging-0.4.7.win32.exe">Windows executable</a> - the latter includes the logging package only). The distribution contains the following files:
   9.711 +<hr>
   9.712 +<table border="0" cellpadding="0" cellspacing="0" width="100%">
   9.713 +<tr><th>Filename</th><th>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th><th>Contents</th></tr>
   9.714 +<tr><td colspan="3">&nbsp;</td></tr>
   9.715 +<tr>
   9.716 +<td><code>README.txt</code></td><td>&nbsp;</td>
   9.717 +<td>Brief description and change history.</td>
   9.718 +</tr>
   9.719 +<tr>
   9.720 +<td><code>__init__.py</code></td><td>&nbsp;</td>
   9.721 +<td>The core logging package itself, including StreamHandler and FileHandler.</td>
   9.722 +</tr>
   9.723 +<tr>
   9.724 +<td><code>handlers.py</code></td><td>&nbsp;</td>
   9.725 +<td>The other handlers provided as part of the package.</td>
   9.726 +</tr>
   9.727 +<tr>
   9.728 +<td><code>config.py</code></td><td>&nbsp;</td>
   9.729 +<td>The code for configuring the package.</td>
   9.730 +</tr>
   9.731 +<tr>
   9.732 +<td><code>setup.py</code></td><td>&nbsp;</td>
   9.733 +<td>The distutils setup script.</td>
   9.734 +</tr>
   9.735 +<tr>
   9.736 +<td><code>logrecv.py</code></td><td>&nbsp;</td>
   9.737 +<td>A test server used for testing SocketHandler, DatagramHandler, HTTPHandler and SOAPHandler. Run it with an argument of one of "TCP", "UDP", "HTTP" or "SOAP" before running a test harness which logs to one of these handlers. Note that to use the SOAP handler, you need to have installed <a href="http://sourceforge.net/projects/pyxml">PyXML-0.6.6</a> and the <a href="http://www.zolera.com/opensrc/zsi/zsi.html">Zolera Soap Infrastructure</a>. This is needed for <code>logrecv.py</code> only, and not for the <code>logging</code> module itself. (Note that ZSI requires Python 2.x)</td>
   9.738 +</tr>
   9.739 +<tr>
   9.740 +<td><code>app.py</code></td><td>&nbsp;</td>
   9.741 +<td>The minimal example described <a href="#simplest">above</a>.</td>
   9.742 +</tr>
   9.743 +<tr>
   9.744 +<td><code>mymodule.py</code></td><td>&nbsp;</td>
   9.745 +<td>Another example described <a href="#nextsimplest">above</a>.</td>
   9.746 +</tr>
   9.747 +<tr>
   9.748 +<td><code>myapp.py</code></td><td>&nbsp;</td>
   9.749 +<td>From the second example described <a href="#nextsimplest">above</a>.</td>
   9.750 +</tr>
   9.751 +<tr>
   9.752 +<td><code>log_test.py</code></td><td>&nbsp;</td>
   9.753 +<td>A test script intended to work as a regression test harness. Runs a number of the other scripts and generates output to stdout.log and stderr.log.</td>
   9.754 +</tr>
   9.755 +<tr>
   9.756 +<td><code>log_test0.py</code></td><td>&nbsp;</td>
   9.757 +<td>A simple test script using <code>basicConfig()</code> only.</td>
   9.758 +</tr>
   9.759 +<tr>
   9.760 +<td><code>log_test1.py</code></td><td>&nbsp;</td>
   9.761 +<td>An example showing slightly more involved configuration and
   9.762 +    exception handling, as well as a Unix syslog handler which uses the standard library's syslog module.</td>
   9.763 +</tr>
   9.764 +<tr>
   9.765 +<td><code>log_test2.py</code></td><td>&nbsp;</td>
   9.766 +<td>A version of <code>log_test0.py</code> which only logs to
   9.767 +    a <code>SocketHandler</code>.</td>
   9.768 +</tr>
   9.769 +<tr>
   9.770 +<td><code>log_test3.py</code></td><td>&nbsp;</td>
   9.771 +<td>An example showing use of <code>fileConfig()</code> and
   9.772 +    logging to various loggers.</td>
   9.773 +</tr>
   9.774 +<tr>
   9.775 +<td><code>log_test4.py</code></td><td>&nbsp;</td>
   9.776 +<td>An example showing use of bespoke levels, filtering by level at logger and handler, and use of filter classes (descendants of <code>Filter</code>).</td>
   9.777 +</tr>
   9.778 +<tr>
   9.779 +<td><code>log_test5.py</code></td><td>&nbsp;</td>
   9.780 +<td>An example showing use of <code>SMTPHandler</code>. Before running this script, be sure to change the bogus addresses it contains to real ones which you have access to.</td>
   9.781 +</tr>
   9.782 +<tr>
   9.783 +<td><code>log_test6.py</code></td><td>&nbsp;</td>
   9.784 +<td>An example showing use of <code>NTEventLogHandler</code>. This script needs to be run on an NT system.</td>
   9.785 +</tr>
   9.786 +<tr>
   9.787 +<td><code>log_test7.py</code></td><td>&nbsp;</td>
   9.788 +<td>An example showing use of <code>MemoryHandler</code>.</td>
   9.789 +</tr>
   9.790 +<tr>
   9.791 +<td><code>log_test8.py</code></td><td>&nbsp;</td>
   9.792 +<td>An example showing use of <code>FileHandler</code> with rollover across multiple files.</td>
   9.793 +</tr>
   9.794 +<tr>
   9.795 +<td><code>log_test9.py</code></td><td>&nbsp;</td>
   9.796 +<td>An example showing use of <code>BufferingHandler</code> and <code>BufferingFormatter</code> through implementing simple <code>XMLFormatter</code> and <code>XMLHandler</code> classes.</td>
   9.797 +</tr>
   9.798 +<tr>
   9.799 +<td><code>log_test10.py</code></td><td>&nbsp;</td>
   9.800 +<td>An example showing how to get the logging module to create loggers of your own class (though it needs to be a subclass of <code>Logger</code>).</td>
   9.801 +</tr>
   9.802 +<tr>
   9.803 +<td><code>log_test11.py</code></td><td>&nbsp;</td>
   9.804 +<td>An example SMTP handler, called <code>BufferingSMTPHandler</code>, which buffers events and sends them via email in batches.</td>
   9.805 +</tr>
   9.806 +<tr>
   9.807 +<td><code>log_test12.py</code></td><td>&nbsp;</td>
   9.808 +<td>An example showing the use of <code>HTTPHandler</code>, for use with <code>logrecv.py</code>.</td>
   9.809 +</tr>
   9.810 +<tr>
   9.811 +<td><code>log_test13.py</code></td><td>&nbsp;</td>
   9.812 +<td>An example showing the use of <code>SOAPHandler</code>, for use with <code>logrecv.py</code>.</td>
   9.813 +</tr>
   9.814 +<tr>
   9.815 +<td><code>log_test14.py</code></td><td>&nbsp;</td>
   9.816 +<td>An example showing an implementation of <code>DBHandler</code>, showing how to log requests to RDBMS tables using the Python Database API 2.0.</td>
   9.817 +</tr>
   9.818 +<tr>
   9.819 +<td><code>log_test15.py</code></td><td>&nbsp;</td>
   9.820 +<td>An example showing the use of the <code>Filter</code> class with a string initializer.</td>
   9.821 +</tr>
   9.822 +<tr>
   9.823 +<td><code>log_test16.py</code></td><td>&nbsp;</td>
   9.824 +<td>An example showing the use of logging in a multi-threaded program.</td>
   9.825 +</tr>
   9.826 +<tr>
   9.827 +<td><code>log_test17.py</code></td><td>&nbsp;</td>
   9.828 +<td>An example showing the use of logging in a multi-threaded program, together with reconfiguring logging on the fly through the use of <code>listen()</code> and <code>stopListening()</code>. This script serves as both server and client, depending on the arguments it's called with.</td>
   9.829 +</tr>
   9.830 +<tr>
   9.831 +<td><code>log_test18.py</code></td><td>&nbsp;</td>
   9.832 +<td>An example showing the use of an example filter, MatchFilter, which offers flexible match-based
   9.833 +filtering of LogRecords.</td>
   9.834 +</tr>
   9.835 +<tr>
   9.836 +<td><code>log_test19.py</code></td><td>&nbsp;</td>
   9.837 +<td>A basic test of logger parents.</td>
   9.838 +</tr>
   9.839 +<tr>
   9.840 +<td><code>log_test20.py</code></td><td>&nbsp;</td>
   9.841 +<td>Demonstrates the use of custom class instances for messages and filtering based on classes.</td>
   9.842 +</tr>
   9.843 +<tr>
   9.844 +<td><code>log_test21.py</code></td><td>&nbsp;</td>
   9.845 +<td>Demonstrates the use of a wildcard name-space filter with and without custom message classes.</td>
   9.846 +</tr>
   9.847 +<tr>
   9.848 +<td><code>log_test22.py</code></td><td>&nbsp;</td>
   9.849 +<td>Demonstrates the use of either localtime or gmtime to do date/time formatting.</td>
   9.850 +</tr>
   9.851 +<tr>
   9.852 +<td><code>debug.ini</code></td><td>&nbsp;</td>
   9.853 +<td>An example configuration for use with log_test17.py.</td>
   9.854 +</tr>
   9.855 +<tr>
   9.856 +<td><code>warn.ini</code></td><td>&nbsp;</td>
   9.857 +<td>An example configuration for use with log_test17.py.</td>
   9.858 +</tr>
   9.859 +<tr>
   9.860 +<td><code>error.ini</code></td><td>&nbsp;</td>
   9.861 +<td>An example configuration for use with log_test17.py.</td>
   9.862 +</tr>
   9.863 +<tr>
   9.864 +<td><code>critical.ini</code></td><td>&nbsp;</td>
   9.865 +<td>An example configuration for use with log_test17.py.</td>
   9.866 +</tr>
   9.867 +<tr>
   9.868 +<td><code>log_test3.ini</code></td><td>&nbsp;</td>
   9.869 +<td>An example configuration for use with log_test3.py.</td>
   9.870 +</tr>
   9.871 +<tr>
   9.872 +<td><code>stdout.exp</code></td><td>&nbsp;</td>
   9.873 +<td>The expected results of stdout.log after running log_test.py.</td>
   9.874 +</tr>
   9.875 +<tr>
   9.876 +<td><code>stderr.exp</code></td><td>&nbsp;</td>
   9.877 +<td>The expected results of stderr.log after running log_test.py.</td>
   9.878 +</tr>
   9.879 +<tr>
   9.880 +<td><code>logconf.py</code></td><td>&nbsp;</td>
   9.881 +<td>A Tkinter-based GUI configurator.</td>
   9.882 +</tr>
   9.883 +<tr>
   9.884 +<td><code>logconf.ini</code></td><td>&nbsp;</td>
   9.885 +<td>Example configuration file, in ConfigParser format, for use with <code>logconf.py</code> and <code>log_test3.py</code>.</td>
   9.886 +</tr>
   9.887 +<tr>
   9.888 +<td><code>logging.dtd</code></td><td>&nbsp;</td>
   9.889 +<td>A simple example DTD for use with <code>log_test9.py</code>.</td>
   9.890 +</tr>
   9.891 +<tr>
   9.892 +<td><code>logging.xml</code></td><td>&nbsp;</td>
   9.893 +<td>An example XML file for use with <code>log_test9.py</code>. It references <code>events.xml</code> as external data.</td>
   9.894 +</tr>
   9.895 +<tr>
   9.896 +<td><code>events.xml</code></td><td>&nbsp;</td>
   9.897 +<td>An example XML file for use with <code>log_test9.py</code>. It holds the actual events in XML format.</td>
   9.898 +</tr>
   9.899 +<tr>
   9.900 +<td><code>python_logging.html</code></td><td>&nbsp;</td>
   9.901 +<td>The page you're reading now.</td>
   9.902 +</tr>
   9.903 +<td><code>default.css</code></td><td>&nbsp;</td>
   9.904 +<td>Stylesheet for use with the HTML pages.</td>
   9.905 +</tr>
   9.906 +<tr><td colspan="3">&nbsp;</td></tr>
   9.907 +</table>
   9.908 +<hr>
   9.909 +<p>To install, unpack the archive into any directory, and in that directory invoke the script <code>"setup.py install"</code> to install the module in the default location used by distutils.</p>
   9.910 +<p>To use, just put <code>logging.py</code> in your Python path, "<code>import logging</code>" and go. (The installation procedure described above will normally put the logging module in your Python path. If you want to use file-based configuration API, you'll also need to <code>import logging.config</code>. To use the more esoteric handlers, you'll also need to <code>import logging.handlers</code>.)</p>
   9.911 +
   9.912 +<a name="changes"></a><h4>Change History</h4>
   9.913 +
   9.914 +<p>The change history is as follows.</p>
   9.915 +
   9.916 +<pre>
   9.917 +Version   Date        Description
   9.918 +=============================================================================
   9.919 +0.4.7     15 Nov 2002 Made into a package with three modules: __init__ (the
   9.920 +                      core code), handlers (all handlers other than
   9.921 +                      FileHandler and its bases) and config (all the config
   9.922 +                      stuff). Before doing this:
   9.923 +                      Updated docstrings to include a short line, then a
   9.924 +                      blank line, then more descriptive text.
   9.925 +                      Renamed 'lvl' to 'level' in various functions.
   9.926 +                      Changed FileHandler to use "a" and "w" instead of "a+"
   9.927 +                      and "w+".
   9.928 +                      Moved log file rotation functionality from FileHandler
   9.929 +                      to a new class RotatingFileHandler.
   9.930 +                      Improved docstring describing rollover.
   9.931 +                      Updated makePickle to use 4-byte length and struct
   9.932 +                      module, likewise logrecv.py. Also updated on-the-fly
   9.933 +                      config reader to use 4-byte length/struct module.
   9.934 +                      Altered ConfigParser test to look at 'readline' rather
   9.935 +                      than 'read'.
   9.936 +                      Added optional "defaults" argument to fileConfig, to
   9.937 +                      be passed to ConfigParser.
   9.938 +                      Renamed ALL to NOTSET to avoid confusion.
   9.939 +                      Commented out getRootLogger(), as obsolete.
   9.940 +                      To do regression testing, run log_test.py and compare
   9.941 +                      the created files stdout.log and stderr.log against
   9.942 +                      the files stdout.exp and stderr.exp. They should match
   9.943 +                      except fir a couple of exception messages which give
   9.944 +                      absolute file paths.
   9.945 +                      Updated python_logging.html to remove links to
   9.946 +                      logging_pydoc.html, which has been removed from the
   9.947 +                      distribution.
   9.948 +                      Changed default for raiseExceptions to 1.
   9.949 +-----------------------------------------------------------------------------
   9.950 +0.4.6     08 Jul 2002 Added raiseExceptions to allow conditional propagation
   9.951 +                      of exceptions which occur during handling.
   9.952 +                      Added converter to Formatter to allow use of any
   9.953 +                      function to convert time from seconds to a tuple. It
   9.954 +                      still defaults to time.localtime but now you can also
   9.955 +                      use time.gmtime.
   9.956 +                      Added log_test22.py to test the conversion feature.
   9.957 +                      Changed rootlogger default level to WARN - was DEBUG.
   9.958 +                      Updated some docstrings.
   9.959 +                      Moved import of threading to where thread is imported.
   9.960 +                      If either is unavailable, threading support is off.
   9.961 +                      Updated minor defects in python_logging.html.
   9.962 +                      Check to see if ConfigParser has readfp method; if it
   9.963 +                      does and an object with a 'read' method is passed in,
   9.964 +                      assumes a file-like object and uses readfp to read it
   9.965 +                      in.
   9.966 +-----------------------------------------------------------------------------
   9.967 +0.4.5     04 Jun 2002 Fixed bug which caused problem if no args to message
   9.968 +                      (suggested by Hye-Shik Chang).
   9.969 +                      Fixed bug in _fixupParents (thanks to Nicholas Veeser)
   9.970 +                      and added log_test19.py as a test case for this bug.
   9.971 +                      Added getMessage to LogRecord (code was moved here from
   9.972 +                      Formatter.format)
   9.973 +                      Applied str() to record.msg to allow arbitrary classes
   9.974 +                      to determine the formatting (as msg can now be a class
   9.975 +                      instance).
   9.976 +                      Table of Contents added to python_logging.html, the
   9.977 +                      section on Loggers updated, and the logconf.ini file
   9.978 +                      section annotated.
   9.979 +                      Added log_test20.py which demonstrates how to use
   9.980 +                      class instances to provide alternatives to numeric
   9.981 +                      severities as mechanisms for control of logging.
   9.982 +                      Added log_test21.py which builds on log_test20.py to
   9.983 +                      show how you can use a regular expression-based Filter
   9.984 +                      for flexible matching similar to e.g. Protomatter
   9.985 +                      Syslog, where you can filter on e.g. "a.*" or "*.b" or
   9.986 +                      "a.*.c".
   9.987 +                      _levelNames changed to contain reverse mappings as well
   9.988 +                      as forward mappings (leveltext->level as well as level
   9.989 +                      -> leveltext). The reverse mappings are used by
   9.990 +                      fileConfig().
   9.991 +                      fileConfig() now more forgiving of missing options in
   9.992 +                      .ini file - sensible defaults now used when some
   9.993 +                      options are absent. Also, eval() is used less when
   9.994 +                      interpreting .ini file contents - int() and dict lookup
   9.995 +                      are used in more places. Altered log_test3.py and added
   9.996 +                      log_test3.ini to show a hand-coded configuration file.
   9.997 +-----------------------------------------------------------------------------
   9.998 +0.4.4     02 May 2002 getEffectiveLevel() returns ALL instead of None when
   9.999 +                      nothing found. Modified references to level=0 to
  9.1000 +                      level=ALL in a couple of places.
  9.1001 +                      SocketHandler now inherits from Handler (it used to
  9.1002 +                      inherit from StreamHandler, for no good reason).
  9.1003 +                      getLock() renamed to createLock().
  9.1004 +                      Docstring tidy-ups, and some tidying up of
  9.1005 +                      DatagramHandler.
  9.1006 +                      Factored out unpickling in logrecv.py.
  9.1007 +                      Added log_test18.py to illustrate MatchFilter, which is
  9.1008 +                      a general matching filter.
  9.1009 +                      Improved FileHandler.doRollover() so that the base
  9.1010 +                      file name is always the most recent, then .1, then .2
  9.1011 +                      etc. up to the maximum backup count. Renamed formal
  9.1012 +                      args and attributes used in rollover.
  9.1013 +                      Changed LogRecord attributes lvl -> levelno, level ->
  9.1014 +                      levelname (less ambiguity)
  9.1015 +                      Formatter.format searches for "%(asctime)" rather than
  9.1016 +                      "(asctime)"
  9.1017 +                      Renamed _start_time to _startTime
  9.1018 +                      Formatter.formatTime now returns the time
  9.1019 +                      Altered logrecv.py to support stopping servers
  9.1020 +                      programmatically
  9.1021 +                      Added log_test.py as overall test harness
  9.1022 +                      basicConfig() can now be safely called more than once
  9.1023 +                      Modified test scripts to make it easier to call them
  9.1024 +                      from log_test.py
  9.1025 +                      Moved SOAPHandler from core to log_test13.py. It's not
  9.1026 +                      general enough to be in the core; most production use
  9.1027 +                      will have differing RPC signatures.
  9.1028 +-----------------------------------------------------------------------------
  9.1029 +0.4.3     14 Apr 2002 Bug fix one-off error message to go to sys.stderr
  9.1030 +                      rather than sys.stdout.
  9.1031 +                      logrecv.py fix TCP for busy network.
  9.1032 +                      Thread safety - added locking to Handler and for shared
  9.1033 +                      data in module, and log_test16.py to test it.
  9.1034 +                      Added socket listener to allow on-the-fly configuration
  9.1035 +                      and added log_test17.py to test it.
  9.1036 +-----------------------------------------------------------------------------
  9.1037 +0.4.2     11 Apr 2002 Bug fix fileConfig() - setup of MemoryHandler target
  9.1038 +                      and errors when loggers have no handlers set or
  9.1039 +                      handlers have no formatters set
  9.1040 +                      logconf.py - seems to hang if window closed when combo
  9.1041 +                      dropdown is showing - added code to close popup on exit
  9.1042 +                      Some tweaks to _srcfile computation (normpath added)
  9.1043 +                      findCaller() optimized, now a lot faster!
  9.1044 +                      Logger.removeHandler now closes the handler before
  9.1045 +                      removing it
  9.1046 +                      fileConfig() removes existing handlers before adding
  9.1047 +                      the new set, to avoid memory leakage when repeated
  9.1048 +                      calls are made
  9.1049 +                      Fixed logrecv.py bug which hogged CPU time when TCP
  9.1050 +                      connection was closed from the client
  9.1051 +                      Added log_test14.py to demonstrate/test a DBHandler
  9.1052 +                      which writes logging records into an RDBMS using the
  9.1053 +                      Python Database API 2.0 (to run, you need something
  9.1054 +                      which supports this already installed - I tested with
  9.1055 +                      mxODBC)
  9.1056 +                      Made getLogger name argument optional - returns root
  9.1057 +                      logger if omitted
  9.1058 +                      Altered Filter to take a string initializer, filtering
  9.1059 +                      a sub-hierarchy rooted at a particular point (idea from
  9.1060 +                      Denis S. Otkidach).
  9.1061 +                      Added log_test15.py to test Filter initializer
  9.1062 +-----------------------------------------------------------------------------
  9.1063 +0.4.1     03 Apr 2002 Bug fix SMTPHandler - extra \r\n needed (Oleg Orlov)
  9.1064 +                      Added BufferingHandler, BufferingFormatter
  9.1065 +                      Renamed getChainedPriority to getEffectiveLevel
  9.1066 +                      Removed Logger.getRoot as it is redundant
  9.1067 +                      Added log_test9.py to test Buffering classes and
  9.1068 +                      to show an XMLFormatter example.
  9.1069 +                      Added setLoggerClass.
  9.1070 +                      Added log_test10.py to test setLoggerClass, using an
  9.1071 +                      example Logger-derived class which outputs exception
  9.1072 +                      info even for DEBUG level logging calls
  9.1073 +                      Added log_test11.py to test a buffering implementation
  9.1074 +                      of SMTPHandler
  9.1075 +                      Changed logging call implementation to allow keyword
  9.1076 +                      arguments (Kevin Butler and others)
  9.1077 +                      Changed default SysLogHandler implementation.
  9.1078 +                      Renamed "additive" to "propagate" as it better
  9.1079 +                      describes the attribute.
  9.1080 +                      Added HTTPHandler.
  9.1081 +                      Modified logrecv.py to remove "both" option and to add
  9.1082 +                      "HTTP" and "SOAP" options (SOAP option needs you to
  9.1083 +                      have PyXML-0.6.6 and ZSI installed - for logrecv.py
  9.1084 +                      only, and not for the core logging module itself).
  9.1085 +                      Added log_test12.py to test HTTPHandler.
  9.1086 +                      Added log_test13.py to test SOAPHandler.
  9.1087 +                      Formatted to Python source guidelines (spaces, indent
  9.1088 +                      of 4, within 80 columns).
  9.1089 +                      More method renamings (result of feedback) - _handle()
  9.1090 +                      renamed to emit(), _logRecord() renamed to handle().
  9.1091 +                      Renamed FATAL to CRITICAL (David Goodger), but left
  9.1092 +                      fatal() and FATAL in (until PEP is changed)
  9.1093 +                      Changed configuration file format to ConfigParser
  9.1094 +                      format.
  9.1095 +                      Factored filter application functionality out to a new
  9.1096 +                      Filterer class. The isLoggable() method is renamed to
  9.1097 +                      filter() in both Filter and Filterer classes.
  9.1098 +                      Altered SMTPHandler __init__ to accept (host, port)
  9.1099 +                      for the mail internet address.
  9.1100 +                      Added GUI configurator which uses Tkinter and the new
  9.1101 +                      configuration file format. (See logconf.py and an
  9.1102 +                      example configuration file in logconf.ini)
  9.1103 +                      Altered log_test3.py to test with the new file format.
  9.1104 +-----------------------------------------------------------------------------
  9.1105 +0.4       21 Mar 2002 Incorporated comments/patches from Ollie Rutherfurd:
  9.1106 +                      -Added level filtering for handlers.
  9.1107 +                      -Return root logger if no name specified in getLogger.
  9.1108 +                      Incorporated comments from Greg Ward:
  9.1109 +                      -Added distutils setup.py script.
  9.1110 +                      Added formatter initialization in Handler.__init__.
  9.1111 +                      Tidied up docstrings.
  9.1112 +                      Added removeHandler to Logger.
  9.1113 +                      Added removeFilter to Logger and Handler.
  9.1114 +                      logrecv.py modified to keep connection alive until
  9.1115 +                      client closes it.
  9.1116 +                      SocketHandler modified to not reset connection after
  9.1117 +                      each logging event.
  9.1118 +                      Added shutdown function which closes open sockets
  9.1119 +                      Renamed DEFAULT_LOGGING_PORT->DEFAULT_TCP_LOGGING_PORT
  9.1120 +                      Added DEFAULT_UDP_LOGGING_PORT
  9.1121 +                      Added log_test4.py (example of arbitrary levels)
  9.1122 +                      Added addLevelName, changed behaviour of getLevelName
  9.1123 +                      Fixed bugs in DatagramHandler
  9.1124 +                      Added SMTPHandler implementation
  9.1125 +                      Added log_test5.py to test SMTPHandler
  9.1126 +                      Added SysLogHandler (contribution from Nicolas Untz
  9.1127 +                      based on Sam Rushing's syslog.py)
  9.1128 +                      Modified log_test1.py to add a SysLogHandler
  9.1129 +                      Added rollover functionality to FileHandler
  9.1130 +                      Added NTEventLogHandler (based on Win32 extensions)
  9.1131 +                      Added MemoryHandler implementation
  9.1132 +                      Added log_test7.py to test MemoryHandler
  9.1133 +                      Added log_test8.py to test FileHandler rollover
  9.1134 +                      Added logException method to Logger
  9.1135 +                      Added formatException method to Formatter
  9.1136 +                      Added log_test6.py to test NTEventHandler and
  9.1137 +                      logException
  9.1138 +                      Numerous internal method renamings (sorry - but better
  9.1139 +                      to do this now, rather than when we enter beta status).
  9.1140 +-----------------------------------------------------------------------------
  9.1141 +0.3       14 Mar 2002 First public release, for early feedback
  9.1142 +-----------------------------------------------------------------------------
  9.1143 +0.2                   Consolidated into single file (for internal use only)
  9.1144 +-----------------------------------------------------------------------------
  9.1145 +0.1                   Initial implementation (for internal use only)
  9.1146 +-----------------------------------------------------------------------------
  9.1147 +</pre>
  9.1148 +
  9.1149 +<a name="license"></a><h4>Copyright and License</h4>
  9.1150 +
  9.1151 +<p>The copyright statement follows. </p>
  9.1152 +
  9.1153 +<pre>
  9.1154 +Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
  9.1155 +
  9.1156 +Permission to use, copy, modify, and distribute this software and its
  9.1157 +documentation for any purpose and without fee is hereby granted,
  9.1158 +provided that the above copyright notice appear in all copies and that
  9.1159 +both that copyright notice and this permission notice appear in
  9.1160 +supporting documentation, and that the name of Vinay Sajip
  9.1161 +not be used in advertising or publicity pertaining to distribution
  9.1162 +of the software without specific, written prior permission.
  9.1163 +VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  9.1164 +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  9.1165 +VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  9.1166 +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  9.1167 +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
  9.1168 +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  9.1169 +
  9.1170 +
  9.1171 +
  9.1172 +
  9.1173 +
  9.1174 +
  9.1175 +
  9.1176 +
  9.1177 +
  9.1178 +
  9.1179 +
  9.1180 +
  9.1181 +
  9.1182 +
  9.1183 +
  9.1184 +</pre>
  9.1185 +</body>
  9.1186 +</html>
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/tools/python/logging/logging-0.4.9.2/setup.py	Thu Jul 22 13:42:39 2004 +0000
    10.3 @@ -0,0 +1,29 @@
    10.4 +from distutils.core import setup
    10.5 +
    10.6 +setup(name = "logging",
    10.7 +            description="A logging module for Python",
    10.8 +            long_description = """This module is intended to provide a standard error logging mechanism in Python as per PEP 282.""",
    10.9 +            license="""Copyright (C) 2001-2004 by Vinay Sajip. All Rights Reserved.
   10.10 +
   10.11 +Permission to use, copy, modify, and distribute this software and its
   10.12 +documentation for any purpose and without fee is hereby granted,
   10.13 +provided that the above copyright notice appear in all copies and that
   10.14 +both that copyright notice and this permission notice appear in
   10.15 +supporting documentation, and that the name of Vinay Sajip
   10.16 +not be used in advertising or publicity pertaining to distribution
   10.17 +of the software without specific, written prior permission.
   10.18 +
   10.19 +VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   10.20 +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   10.21 +VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   10.22 +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
   10.23 +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
   10.24 +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.""",
   10.25 +            version = "0.4.9.2",
   10.26 +            author = "Vinay Sajip",
   10.27 +            author_email = "vinay_sajip@red-dove.com",
   10.28 +            maintainer = "Vinay Sajip",
   10.29 +            maintainer_email = "vinay_sajip@red-dove.com",
   10.30 +            url = "http://www.red-dove.com/python_logging.html",
   10.31 +            packages = ["logging"],
   10.32 +            )
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/tools/python/logging/logging-0.4.9.2/test/app.py	Thu Jul 22 13:42:39 2004 +0000
    11.3 @@ -0,0 +1,5 @@
    11.4 +import logging
    11.5 +
    11.6 +logging.warning("Hello")
    11.7 +logging.error("Still here...")
    11.8 +logging.warning("Goodbye")
    11.9 \ No newline at end of file
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/tools/python/logging/logging-0.4.9.2/test/critical.ini	Thu Jul 22 13:42:39 2004 +0000
    12.3 @@ -0,0 +1,60 @@
    12.4 +[loggers]
    12.5 +keys=root,log02,log03,log04,log05
    12.6 +
    12.7 +[handlers]
    12.8 +keys=hand01
    12.9 +
   12.10 +[formatters]
   12.11 +keys=form01
   12.12 +
   12.13 +[logger_root]
   12.14 +level=WARN
   12.15 +propagate=1
   12.16 +channel=
   12.17 +parent=
   12.18 +qualname=(root)
   12.19 +handlers=hand01
   12.20 +
   12.21 +[logger_log02]
   12.22 +level=CRITICAL
   12.23 +propagate=1
   12.24 +channel=A
   12.25 +parent=(root)
   12.26 +qualname=A
   12.27 +handlers=
   12.28 +
   12.29 +[logger_log03]
   12.30 +level=CRITICAL
   12.31 +propagate=1
   12.32 +channel=B
   12.33 +parent=log02
   12.34 +qualname=A.B
   12.35 +handlers=
   12.36 +
   12.37 +[logger_log04]
   12.38 +level=CRITICAL
   12.39 +propagate=1
   12.40 +channel=C
   12.41 +parent=log03
   12.42 +qualname=A.B.C
   12.43 +handlers=
   12.44 +
   12.45 +[logger_log05]
   12.46 +level=CRITICAL
   12.47 +propagate=1
   12.48 +channel=D
   12.49 +parent=log04
   12.50 +qualname=A.B.C.D
   12.51 +handlers=
   12.52 +
   12.53 +[handler_hand01]
   12.54 +class=StreamHandler
   12.55 +level=NOTSET
   12.56 +formatter=form01
   12.57 +stream=sys.stderr
   12.58 +args=(sys.stderr,)
   12.59 +
   12.60 +[formatter_form01]
   12.61 +format=critical.ini %(name)s %(levelname)s %(message)s
   12.62 +datefmt=
   12.63 +
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/tools/python/logging/logging-0.4.9.2/test/debug.ini	Thu Jul 22 13:42:39 2004 +0000
    13.3 @@ -0,0 +1,60 @@
    13.4 +[loggers]
    13.5 +keys=root,log02,log03,log04,log05
    13.6 +
    13.7 +[handlers]
    13.8 +keys=hand01
    13.9 +
   13.10 +[formatters]
   13.11 +keys=form01
   13.12 +
   13.13 +[logger_root]
   13.14 +level=WARN
   13.15 +propagate=1
   13.16 +channel=
   13.17 +parent=
   13.18 +qualname=(root)
   13.19 +handlers=hand01
   13.20 +
   13.21 +[logger_log02]
   13.22 +level=DEBUG
   13.23 +propagate=1
   13.24 +channel=A
   13.25 +parent=(root)
   13.26 +qualname=A
   13.27 +handlers=
   13.28 +
   13.29 +[logger_log03]
   13.30 +level=DEBUG
   13.31 +propagate=1
   13.32 +channel=B
   13.33 +parent=log02
   13.34 +qualname=A.B
   13.35 +handlers=
   13.36 +
   13.37 +[logger_log04]
   13.38 +level=DEBUG
   13.39 +propagate=1
   13.40 +channel=C
   13.41 +parent=log03
   13.42 +qualname=A.B.C
   13.43 +handlers=
   13.44 +
   13.45 +[logger_log05]
   13.46 +level=DEBUG
   13.47 +propagate=1
   13.48 +channel=D
   13.49 +parent=log04
   13.50 +qualname=A.B.C.D
   13.51 +handlers=
   13.52 +
   13.53 +[handler_hand01]
   13.54 +class=StreamHandler
   13.55 +level=NOTSET
   13.56 +formatter=form01
   13.57 +stream=sys.stderr
   13.58 +args=(sys.stderr,)
   13.59 +
   13.60 +[formatter_form01]
   13.61 +format=debug.ini %(name)s %(levelname)s %(message)s
   13.62 +datefmt=
   13.63 +
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/tools/python/logging/logging-0.4.9.2/test/error.ini	Thu Jul 22 13:42:39 2004 +0000
    14.3 @@ -0,0 +1,60 @@
    14.4 +[loggers]
    14.5 +keys=root,log02,log03,log04,log05
    14.6 +
    14.7 +[handlers]
    14.8 +keys=hand01
    14.9 +
   14.10 +[formatters]
   14.11 +keys=form01
   14.12 +
   14.13 +[logger_root]
   14.14 +level=WARN
   14.15 +propagate=1
   14.16 +channel=
   14.17 +parent=
   14.18 +qualname=(root)
   14.19 +handlers=hand01
   14.20 +
   14.21 +[logger_log02]
   14.22 +level=ERROR
   14.23 +propagate=1
   14.24 +channel=A
   14.25 +parent=(root)
   14.26 +qualname=A
   14.27 +handlers=
   14.28 +
   14.29 +[logger_log03]
   14.30 +level=ERROR
   14.31 +propagate=1
   14.32 +channel=B
   14.33 +parent=log02
   14.34 +qualname=A.B
   14.35 +handlers=
   14.36 +
   14.37 +[logger_log04]
   14.38 +level=ERROR
   14.39 +propagate=1
   14.40 +channel=C
   14.41 +parent=log03
   14.42 +qualname=A.B.C
   14.43 +handlers=
   14.44 +
   14.45 +[logger_log05]
   14.46 +level=ERROR
   14.47 +propagate=1
   14.48 +channel=D
   14.49 +parent=log04
   14.50 +qualname=A.B.C.D
   14.51 +handlers=
   14.52 +
   14.53 +[handler_hand01]
   14.54 +class=StreamHandler
   14.55 +level=NOTSET
   14.56 +formatter=form01
   14.57 +stream=sys.stderr
   14.58 +args=(sys.stderr,)
   14.59 +
   14.60 +[formatter_form01]
   14.61 +format=error.ini %(name)s %(levelname)s %(message)s
   14.62 +datefmt=
   14.63 +
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/tools/python/logging/logging-0.4.9.2/test/events.xml	Thu Jul 22 13:42:39 2004 +0000
    15.3 @@ -0,0 +1,31 @@
    15.4 +
    15.5 +    <event name="root" level="20" filename="log_test9.py" lineno="66">
    15.6 +    <message>Info index = 90</message>
    15.7 +    </event>
    15.8 +    <event name="root" level="20" filename="log_test9.py" lineno="66">
    15.9 +    <message>Info index = 91</message>
   15.10 +    </event>
   15.11 +    <event name="root" level="20" filename="log_test9.py" lineno="66">
   15.12 +    <message>Info index = 92</message>
   15.13 +    </event>
   15.14 +    <event name="root" level="20" filename="log_test9.py" lineno="66">
   15.15 +    <message>Info index = 93</message>
   15.16 +    </event>
   15.17 +    <event name="root" level="20" filename="log_test9.py" lineno="66">
   15.18 +    <message>Info index = 94</message>
   15.19 +    </event>
   15.20 +    <event name="root" level="20" filename="log_test9.py" lineno="66">
   15.21 +    <message>Info index = 95</message>
   15.22 +    </event>
   15.23 +    <event name="root" level="20" filename="log_test9.py" lineno="66">
   15.24 +    <message>Info index = 96</message>
   15.25 +    </event>
   15.26 +    <event name="root" level="20" filename="log_test9.py" lineno="66">
   15.27 +    <message>Info index = 97</message>
   15.28 +    </event>
   15.29 +    <event name="root" level="20" filename="log_test9.py" lineno="66">
   15.30 +    <message>Info index = 98</message>
   15.31 +    </event>
   15.32 +    <event name="root" level="20" filename="log_test9.py" lineno="66">
   15.33 +    <message>Info index = 99</message>
   15.34 +    </event>
   15.35 \ No newline at end of file
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test.py	Thu Jul 22 13:42:39 2004 +0000
    16.3 @@ -0,0 +1,158 @@
    16.4 +#!/usr/bin/env python
    16.5 +#
    16.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    16.7 +#
    16.8 +# Permission to use, copy, modify, and distribute this software and its
    16.9 +# documentation for any purpose and without fee is hereby granted,
   16.10 +# provided that the above copyright notice appear in all copies and that
   16.11 +# both that copyright notice and this permission notice appear in
   16.12 +# supporting documentation, and that the name of Vinay Sajip
   16.13 +# not be used in advertising or publicity pertaining to distribution
   16.14 +# of the software without specific, written prior permission.
   16.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   16.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   16.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   16.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   16.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   16.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16.21 +#
   16.22 +# This file is part of the Python logging distribution. See
   16.23 +# http://www.red-dove.com/python_logging.html
   16.24 +#
   16.25 +"""Test harness for the logging module. Run all tests.
   16.26 +
   16.27 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   16.28 +"""
   16.29 +
   16.30 +import os, sys, logging, threading, time
   16.31 +
   16.32 +BANNER = "-- %-10s %-6s --------------------------------------------------------\n"
   16.33 +
   16.34 +def banner(nm, typ):
   16.35 +    sep = BANNER % (nm, typ)
   16.36 +    sys.stdout.write(sep)
   16.37 +    sys.stdout.flush()
   16.38 +    sys.stderr.write(sep)
   16.39 +    sys.stderr.flush()
   16.40 +
   16.41 +def main():
   16.42 +    oldout = sys.stdout
   16.43 +    olderr = sys.stderr
   16.44 +    sys.stdout = open("stdout.log", "w")
   16.45 +    sys.stderr = open("stderr.log", "w")
   16.46 +    logging.basicConfig()
   16.47 +    root = logging.getLogger("")
   16.48 +    hdlr0 = root.handlers[0]
   16.49 +    #Set up servers
   16.50 +    import logrecv
   16.51 +    threads = []
   16.52 +    tcpserver = logrecv.LogRecordSocketReceiver()
   16.53 +    tcpserver.logname = ""
   16.54 +    threads.append(threading.Thread(target=logrecv.runTCP, args=(tcpserver,)))
   16.55 +    udpserver = logrecv.LogRecordDatagramReceiver()
   16.56 +    udpserver.logname = ""
   16.57 +    threads.append(threading.Thread(target=logrecv.runUDP, args=(udpserver,)))
   16.58 +    httpserver = logrecv.LogRecordHTTPReceiver()
   16.59 +    httpserver.logname = ""
   16.60 +    threads.append(threading.Thread(target=logrecv.runHTTP, args=(httpserver,)))
   16.61 +    soapserver = None
   16.62 +    if logrecv.SOAPServer:
   16.63 +        soapserver = logrecv.SOAPServer()
   16.64 +        soapserver.modules = (sys.modules["logrecv"],)
   16.65 +        soapserver.logname = ""
   16.66 +        threads.append(threading.Thread(target=logrecv.runSOAP, args=(soapserver,)))
   16.67 +
   16.68 +    for thread in threads:
   16.69 +        thread.start()
   16.70 +    try:
   16.71 +        import log_test0
   16.72 +        banner("log_test0", "begin")
   16.73 +        log_test0.main()
   16.74 +        banner("log_test0", "end")
   16.75 +        try:
   16.76 +            import log_test1
   16.77 +            banner("log_test1", "begin")
   16.78 +            log_test1.main()
   16.79 +            banner("log_test1", "end")
   16.80 +        except ImportError:
   16.81 +            pass
   16.82 +
   16.83 +        import log_test2
   16.84 +        banner("log_test2", "begin")
   16.85 +        log_test2.main()
   16.86 +        banner("log_test2", "end")
   16.87 +        time.sleep(3)
   16.88 +
   16.89 +        #Skip 3 as it tests fileConfig
   16.90 +
   16.91 +        banner("log_test4", "begin")
   16.92 +        import log_test4
   16.93 +        banner("log_test4", "end")
   16.94 +
   16.95 +        #Skip 5 as it tests SMTPHandler, can't easily check results automatically
   16.96 +
   16.97 +        #Skip 6 as it tests NTEventLogHandler, can't easily check results automatically
   16.98 +
   16.99 +        banner("log_test7", "begin")
  16.100 +        root.removeHandler(hdlr0)
  16.101 +        import log_test7
  16.102 +        root.addHandler(hdlr0)
  16.103 +        banner("log_test7", "end")
  16.104 +
  16.105 +        banner("log_test8", "begin")
  16.106 +        import log_test8
  16.107 +        root.removeHandler(hdlr0)
  16.108 +        log_test8.main()
  16.109 +        root.addHandler(hdlr0)
  16.110 +        banner("log_test8", "end")
  16.111 +
  16.112 +        banner("log_test9", "begin")
  16.113 +        import log_test9
  16.114 +        root.removeHandler(hdlr0)
  16.115 +        log_test9.main()
  16.116 +        root.addHandler(hdlr0)
  16.117 +        banner("log_test9", "end")
  16.118 +
  16.119 +        banner("log_test10", "begin")
  16.120 +        import log_test10
  16.121 +        log_test10.main()
  16.122 +        banner("log_test10", "end")
  16.123 +
  16.124 +        #Skip 11 as it tests SMTPHandler, can't easily check results automatically
  16.125 +
  16.126 +        import log_test12
  16.127 +        banner("log_test12", "begin")
  16.128 +        log_test12.main()
  16.129 +        banner("log_test12", "end")
  16.130 +
  16.131 +        import log_test13
  16.132 +        banner("log_test13", "begin")
  16.133 +        log_test13.main()
  16.134 +        banner("log_test13", "end")
  16.135 +
  16.136 +        import log_test15
  16.137 +        banner("log_test15", "begin")
  16.138 +        log_test15.test(log_test15.FILTER)
  16.139 +        banner("log_test15", "end")
  16.140 +
  16.141 +        time.sleep(3)
  16.142 +
  16.143 +    finally:
  16.144 +        #shut down servers
  16.145 +        olderr.write("Tidying up...")
  16.146 +        tcpserver.abort = 1
  16.147 +        udpserver.abort = 1
  16.148 +        httpserver.abort = 1
  16.149 +        if soapserver:
  16.150 +            soapserver.abort = 1
  16.151 +        for thread in threads:
  16.152 +            thread.join()
  16.153 +        sys.stdout.close()
  16.154 +        sys.stdout = oldout
  16.155 +        #don't close this, as hdlr0 references it. hdlr0 will be closed at application exit
  16.156 +        #sys.stderr.close()
  16.157 +        sys.stderr = olderr
  16.158 +        print "Test run completed."
  16.159 +
  16.160 +if __name__ == "__main__":
  16.161 +    main()
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test0.py	Thu Jul 22 13:42:39 2004 +0000
    17.3 @@ -0,0 +1,118 @@
    17.4 +#!/usr/bin/env python
    17.5 +#
    17.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    17.7 +#
    17.8 +# Permission to use, copy, modify, and distribute this software and its
    17.9 +# documentation for any purpose and without fee is hereby granted,
   17.10 +# provided that the above copyright notice appear in all copies and that
   17.11 +# both that copyright notice and this permission notice appear in
   17.12 +# supporting documentation, and that the name of Vinay Sajip
   17.13 +# not be used in advertising or publicity pertaining to distribution
   17.14 +# of the software without specific, written prior permission.
   17.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   17.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   17.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   17.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   17.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   17.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17.21 +#
   17.22 +# This file is part of the Python logging distribution. See
   17.23 +# http://www.red-dove.com/python_logging.html
   17.24 +#
   17.25 +"""Test harness for the logging module. A basic test of levels.
   17.26 +
   17.27 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   17.28 +"""
   17.29 +
   17.30 +import logging
   17.31 +msgcount = 0
   17.32 +
   17.33 +def nextmessage():
   17.34 +    global msgcount
   17.35 +    rv = "Message %d" % msgcount
   17.36 +    msgcount = msgcount + 1
   17.37 +    return rv
   17.38 +
   17.39 +def main():
   17.40 +    logging.basicConfig()
   17.41 +    logging.getLogger("").setLevel(logging.DEBUG)
   17.42 +    ERR = logging.getLogger("ERR")
   17.43 +    ERR.setLevel(logging.ERROR)
   17.44 +    INF = logging.getLogger("INF")
   17.45 +    INF.setLevel(logging.INFO)
   17.46 +    INF_ERR  = logging.getLogger("INF.ERR")
   17.47 +    INF_ERR.setLevel(logging.ERROR)
   17.48 +    DEB = logging.getLogger("DEB")
   17.49 +    DEB.setLevel(logging.DEBUG)
   17.50 +
   17.51 +    INF_UNDEF = logging.getLogger("INF.UNDEF")
   17.52 +    INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
   17.53 +    UNDEF = logging.getLogger("UNDEF")
   17.54 +
   17.55 +    GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
   17.56 +    CHILD = logging.getLogger("INF.BADPARENT")
   17.57 +
   17.58 +    #These should log
   17.59 +    ERR.log(logging.CRITICAL, nextmessage())
   17.60 +    ERR.error(nextmessage())
   17.61 +
   17.62 +    INF.log(logging.CRITICAL, nextmessage())
   17.63 +    INF.error(nextmessage())
   17.64 +    INF.warning(nextmessage())
   17.65 +    INF.info(nextmessage())
   17.66 +
   17.67 +    INF_UNDEF.log(logging.CRITICAL, nextmessage())
   17.68 +    INF_UNDEF.error(nextmessage())
   17.69 +    INF_UNDEF.warning(nextmessage())
   17.70 +    INF_UNDEF.info(nextmessage())
   17.71 +
   17.72 +    INF_ERR.log(logging.CRITICAL, nextmessage())
   17.73 +    INF_ERR.error(nextmessage())
   17.74 +
   17.75 +    INF_ERR_UNDEF.log(logging.CRITICAL, nextmessage())
   17.76 +    INF_ERR_UNDEF.error(nextmessage())
   17.77 +
   17.78 +    DEB.log(logging.CRITICAL, nextmessage())
   17.79 +    DEB.error(nextmessage())
   17.80 +    DEB.warning(nextmessage())
   17.81 +    DEB.info(nextmessage())
   17.82 +    DEB.debug(nextmessage())
   17.83 +
   17.84 +    UNDEF.log(logging.CRITICAL, nextmessage())
   17.85 +    UNDEF.error(nextmessage())
   17.86 +    UNDEF.warning(nextmessage())
   17.87 +    UNDEF.info(nextmessage())
   17.88 +
   17.89 +    GRANDCHILD.log(logging.CRITICAL, nextmessage())
   17.90 +    CHILD.log(logging.CRITICAL, nextmessage())
   17.91 +
   17.92 +    #These should not log
   17.93 +    ERR.warning(nextmessage())
   17.94 +    ERR.info(nextmessage())
   17.95 +    ERR.debug(nextmessage())
   17.96 +
   17.97 +    INF.debug(nextmessage())
   17.98 +    INF_UNDEF.debug(nextmessage())
   17.99 +
  17.100 +    INF_ERR.warning(nextmessage())
  17.101 +    INF_ERR.info(nextmessage())
  17.102 +    INF_ERR.debug(nextmessage())
  17.103 +    INF_ERR_UNDEF.warning(nextmessage())
  17.104 +    INF_ERR_UNDEF.info(nextmessage())
  17.105 +    INF_ERR_UNDEF.debug(nextmessage())
  17.106 +
  17.107 +    INF.info("Messages should bear numbers 0 through 24.")
  17.108 +
  17.109 +if __name__ == "__main__":
  17.110 +    import sys
  17.111 +    #print sys.argv[0]
  17.112 +    args = sys.argv[1:]
  17.113 +    if "-profile" in args:
  17.114 +        import profile, pstats
  17.115 +        args.remove("-profile")
  17.116 +        statf = "log_test0.pro"
  17.117 +        profile.run("main()", statf)
  17.118 +        stats = pstats.Stats(statf)
  17.119 +        stats.strip_dirs().sort_stats('time').print_stats()
  17.120 +    else:
  17.121 +        main()
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test1.py	Thu Jul 22 13:42:39 2004 +0000
    18.3 @@ -0,0 +1,85 @@
    18.4 +#!/usr/bin/env python
    18.5 +#
    18.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    18.7 +#
    18.8 +# Permission to use, copy, modify, and distribute this software and its
    18.9 +# documentation for any purpose and without fee is hereby granted,
   18.10 +# provided that the above copyright notice appear in all copies and that
   18.11 +# both that copyright notice and this permission notice appear in
   18.12 +# supporting documentation, and that the name of Vinay Sajip
   18.13 +# not be used in advertising or publicity pertaining to distribution
   18.14 +# of the software without specific, written prior permission.
   18.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   18.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   18.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   18.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   18.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   18.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18.21 +#
   18.22 +# This file is part of the Python logging distribution. See
   18.23 +# http://www.red-dove.com/python_logging.html
   18.24 +#
   18.25 +"""Test harness for the logging module. A test showing exception handling and use of SysLogHandler.
   18.26 +
   18.27 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   18.28 +"""
   18.29 +import sys, logging
   18.30 +import syslog
   18.31 +
   18.32 +class SLHandler(logging.Handler):
   18.33 +    def __init__(self, ident, logopt=0, facility=syslog.LOG_USER):
   18.34 +        logging.Handler.__init__(self)
   18.35 +        self.ident = ident
   18.36 +        self.logopt = logopt
   18.37 +        self.facility = facility
   18.38 +        self.mappings = {
   18.39 +            logging.DEBUG: syslog.LOG_DEBUG,
   18.40 +            logging.INFO: syslog.LOG_INFO,
   18.41 +            logging.WARNING: syslog.LOG_WARNING,
   18.42 +            logging.ERROR: syslog.LOG_ERR,
   18.43 +            logging.CRITICAL: syslog.LOG_CRIT,
   18.44 +            }
   18.45 +
   18.46 +    def encodeLevel(self, level):
   18.47 +        return self.mappings.get(level, syslog.LOG_INFO)
   18.48 +
   18.49 +    def emit(self, record):
   18.50 +        syslog.openlog(self.ident, self.logopt, self.facility)
   18.51 +        msg = self.format(record)
   18.52 +        prio = self.encodeLevel(record.levelno)
   18.53 +        syslog.syslog(prio, msg)
   18.54 +        syslog.closelog()
   18.55 +
   18.56 +def config():
   18.57 +    logging.basicConfig()
   18.58 +    logging.getLogger("").setLevel(logging.DEBUG)
   18.59 +    if __name__ == "__main__":
   18.60 +        fmt = logging.Formatter("%(asctime)s %(filename)s:%(lineno)d %(levelname)-5s - %(message)s")
   18.61 +        hdlr = logging.FileHandler("tmp.tmp")
   18.62 +        hdlr.setFormatter(fmt)
   18.63 +        logging.getLogger("").addHandler(hdlr)
   18.64 +    else:
   18.65 +        fmt = None
   18.66 +    hdlr = SLHandler("log_test1")
   18.67 +    if fmt:
   18.68 +        hdlr.setFormatter(fmt)
   18.69 +    logging.getLogger("").addHandler(hdlr)
   18.70 +    return hdlr
   18.71 +
   18.72 +def run():
   18.73 +    logging.info("Starting...")
   18.74 +    try:
   18.75 +        print "7" + 4
   18.76 +    except Exception, e:
   18.77 +        logging.error("Problem %s (%d)", "ERROR", logging.ERROR, exc_info=1)
   18.78 +        logging.debug("Problem %s (%d)", "DEBUG", logging.DEBUG, exc_info=1)
   18.79 +    logging.info("Done.")
   18.80 +
   18.81 +
   18.82 +def main():
   18.83 +    hdlr = config()
   18.84 +    run()
   18.85 +    logging.getLogger("").removeHandler(hdlr)
   18.86 +
   18.87 +if __name__ == "__main__":
   18.88 +    main()
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test10.py	Thu Jul 22 13:42:39 2004 +0000
    19.3 @@ -0,0 +1,87 @@
    19.4 +#!/usr/bin/env python
    19.5 +#
    19.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    19.7 +#
    19.8 +# Permission to use, copy, modify, and distribute this software and its
    19.9 +# documentation for any purpose and without fee is hereby granted,
   19.10 +# provided that the above copyright notice appear in all copies and that
   19.11 +# both that copyright notice and this permission notice appear in
   19.12 +# supporting documentation, and that the name of Vinay Sajip
   19.13 +# not be used in advertising or publicity pertaining to distribution
   19.14 +# of the software without specific, written prior permission.
   19.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   19.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   19.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   19.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   19.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   19.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   19.21 +#
   19.22 +# This file is part of the Python logging distribution. See
   19.23 +# http://www.red-dove.com/python_logging.html
   19.24 +#
   19.25 +"""Test harness for the logging module. Shows use of a user-defined Logger subclass.
   19.26 +
   19.27 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   19.28 +"""
   19.29 +import sys
   19.30 +import locale
   19.31 +
   19.32 +locale.setlocale(locale.LC_ALL, '')
   19.33 +
   19.34 +from logging import *
   19.35 +
   19.36 +LOG_FORMAT = "%(asctime)s %(levelname)-5s %(message)s"
   19.37 +DATE_FORMAT = "%x %X"
   19.38 +
   19.39 +class MyLogger(Logger):
   19.40 +    """
   19.41 +    A simple example of a logger extension.
   19.42 +    """
   19.43 +    def debug(self, msg, *args, **kwargs):
   19.44 +        """
   19.45 +        This overridden method passes exception information for DEBUG level calls
   19.46 +        """
   19.47 +        if self.manager.disable >= DEBUG:
   19.48 +            return
   19.49 +        if DEBUG >= self.getEffectiveLevel():
   19.50 +            exc_info = kwargs.get("exc_info", 0)
   19.51 +            ei = None
   19.52 +            if exc_info:
   19.53 +                ei = sys.exc_info()
   19.54 +                if not ei[1]:
   19.55 +                    ei = None
   19.56 +            self._log(DEBUG, msg, args, ei)
   19.57 +            del ei
   19.58 +
   19.59 +class NotALogger:
   19.60 +    pass
   19.61 +
   19.62 +def config():
   19.63 +    try:
   19.64 +        setLoggerClass(NotALogger)
   19.65 +    except Exception, e:
   19.66 +        sys.stderr.write("%s\n" % e)
   19.67 +    setLoggerClass(MyLogger)
   19.68 +    if __name__ == "__main__":
   19.69 +        basicConfig()
   19.70 +    if __name__ == "__main__":
   19.71 +        getLogger("").handlers[0].setFormatter(Formatter(LOG_FORMAT, DATE_FORMAT))
   19.72 +
   19.73 +def run():
   19.74 +    getLogger("").setLevel(DEBUG)
   19.75 +    logger = getLogger("mylogger")
   19.76 +    logger.info("Starting...")
   19.77 +    logger.debug("Debug message not in exception handler (no traceback)")
   19.78 +    logger.info("About to throw exception...")
   19.79 +    try:
   19.80 +        print "7" + 4
   19.81 +    except Exception, e:
   19.82 +        logger.debug("Debug message inside exception handler (traceback)",exc_info=1)
   19.83 +    logger.info("Done.")
   19.84 +
   19.85 +def main():
   19.86 +    config()
   19.87 +    run()
   19.88 +
   19.89 +if __name__ == "__main__":
   19.90 +    main()
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test11.py	Thu Jul 22 13:42:39 2004 +0000
    20.3 @@ -0,0 +1,72 @@
    20.4 +#!/usr/bin/env python
    20.5 +#
    20.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    20.7 +#
    20.8 +# Permission to use, copy, modify, and distribute this software and its
    20.9 +# documentation for any purpose and without fee is hereby granted,
   20.10 +# provided that the above copyright notice appear in all copies and that
   20.11 +# both that copyright notice and this permission notice appear in
   20.12 +# supporting documentation, and that the name of Vinay Sajip
   20.13 +# not be used in advertising or publicity pertaining to distribution
   20.14 +# of the software without specific, written prior permission.
   20.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   20.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   20.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   20.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   20.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   20.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   20.21 +#
   20.22 +# This file is part of the Python logging distribution. See
   20.23 +# http://www.red-dove.com/python_logging.html
   20.24 +#
   20.25 +"""Test harness for the logging module. Tests BufferingSMTPHandler, an alternative implementation
   20.26 +of SMTPHandler.
   20.27 +
   20.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   20.29 +"""
   20.30 +import string, logging, logging.handlers
   20.31 +
   20.32 +MAILHOST = 'beta'
   20.33 +FROM     = 'log_test11@red-dove.com'
   20.34 +TO       = ['arkadi_renko']
   20.35 +SUBJECT  = 'Test Logging email from Python logging module (buffering)'
   20.36 +
   20.37 +class BufferingSMTPHandler(logging.handlers.BufferingHandler):
   20.38 +    def __init__(self, mailhost, fromaddr, toaddrs, subject, capacity):
   20.39 +        logging.handlers.BufferingHandler.__init__(self, capacity)
   20.40 +        self.mailhost = mailhost
   20.41 +        self.mailport = None
   20.42 +        self.fromaddr = fromaddr
   20.43 +        self.toaddrs = toaddrs
   20.44 +        self.subject = subject
   20.45 +        self.setFormatter(logging.Formatter("%(asctime)s %(levelname)-5s %(message)s"))
   20.46 +
   20.47 +    def flush(self):
   20.48 +        if len(self.buffer) > 0:
   20.49 +            try:
   20.50 +                import smtplib
   20.51 +                port = self.mailport
   20.52 +                if not port:
   20.53 +                    port = smtplib.SMTP_PORT
   20.54 +                smtp = smtplib.SMTP(self.mailhost, port)
   20.55 +                msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n" % (self.fromaddr, string.join(self.toaddrs, ","), self.subject)
   20.56 +                for record in self.buffer:
   20.57 +                    s = self.format(record)
   20.58 +                    print s
   20.59 +                    msg = msg + s + "\r\n"
   20.60 +                smtp.sendmail(self.fromaddr, self.toaddrs, msg)
   20.61 +                smtp.quit()
   20.62 +            except:
   20.63 +                self.handleError(None)  # no particular record
   20.64 +            self.buffer = []
   20.65 +
   20.66 +def test():
   20.67 +    logger = logging.getLogger("")
   20.68 +    logger.setLevel(logging.DEBUG)
   20.69 +    logger.addHandler(BufferingSMTPHandler(MAILHOST, FROM, TO, SUBJECT, 10))
   20.70 +    for i in xrange(102):
   20.71 +        logger.info("Info index = %d", i)
   20.72 +    logging.shutdown()
   20.73 +
   20.74 +if __name__ == "__main__":
   20.75 +    test()
   20.76 \ No newline at end of file
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test12.py	Thu Jul 22 13:42:39 2004 +0000
    21.3 @@ -0,0 +1,47 @@
    21.4 +#!/usr/bin/env python
    21.5 +#
    21.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    21.7 +#
    21.8 +# Permission to use, copy, modify, and distribute this software and its
    21.9 +# documentation for any purpose and without fee is hereby granted,
   21.10 +# provided that the above copyright notice appear in all copies and that
   21.11 +# both that copyright notice and this permission notice appear in
   21.12 +# supporting documentation, and that the name of Vinay Sajip
   21.13 +# not be used in advertising or publicity pertaining to distribution
   21.14 +# of the software without specific, written prior permission.
   21.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   21.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   21.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   21.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   21.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   21.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   21.21 +#
   21.22 +# This file is part of the Python logging distribution. See
   21.23 +# http://www.red-dove.com/python_logging.html
   21.24 +#
   21.25 +"""
   21.26 +A test harness for the logging module. Tests HTTPHandler.
   21.27 +
   21.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   21.29 +"""
   21.30 +import sys, string, logging, logging.handlers
   21.31 +
   21.32 +def main():
   21.33 +    import pdb
   21.34 +    host = "localhost:%d" % logging.handlers.DEFAULT_HTTP_LOGGING_PORT
   21.35 +    gh = logging.handlers.HTTPHandler(host, '/log', 'GET')
   21.36 +    ph = logging.handlers.HTTPHandler(host, '/log', 'POST')
   21.37 +    logger = logging.getLogger("log_test12")
   21.38 +    logger.propagate = 0
   21.39 +    logger.addHandler(gh)
   21.40 +    logger.addHandler(ph)
   21.41 +    logging.getLogger("").setLevel(logging.DEBUG)
   21.42 +    logger.info("Jackdaws love my big %s of %s", "sphinx", "quartz")
   21.43 +    logger.debug("Pack my %s with twelve dozen %s", "box", "liquor jugs")
   21.44 +    gh.close()
   21.45 +    ph.close()
   21.46 +    logger.removeHandler(gh)
   21.47 +    logger.removeHandler(ph)
   21.48 +
   21.49 +if __name__ == "__main__":
   21.50 +    main()
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test13.py	Thu Jul 22 13:42:39 2004 +0000
    22.3 @@ -0,0 +1,106 @@
    22.4 +#!/usr/bin/env python
    22.5 +#
    22.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    22.7 +#
    22.8 +# Permission to use, copy, modify, and distribute this software and its
    22.9 +# documentation for any purpose and without fee is hereby granted,
   22.10 +# provided that the above copyright notice appear in all copies and that
   22.11 +# both that copyright notice and this permission notice appear in
   22.12 +# supporting documentation, and that the name of Vinay Sajip
   22.13 +# not be used in advertising or publicity pertaining to distribution
   22.14 +# of the software without specific, written prior permission.
   22.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   22.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   22.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   22.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   22.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   22.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   22.21 +#
   22.22 +# This file is part of the Python logging distribution. See
   22.23 +# http://www.red-dove.com/python_logging.html
   22.24 +#
   22.25 +"""
   22.26 +A test harness for the logging module. Implements a SOAPHandler class which
   22.27 +can be used to form the basis of extended SOAP functionality.
   22.28 +
   22.29 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   22.30 +"""
   22.31 +import string, logging, logging.handlers, types
   22.32 +
   22.33 +SOAP_MESSAGE = """<SOAP-ENV:Envelope
   22.34 +    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
   22.35 +    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   22.36 +    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   22.37 +    xmlns:logging="http://www.red-dove.com/logging"
   22.38 +    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
   22.39 +>
   22.40 +    <SOAP-ENV:Body>
   22.41 +        <logging:log>
   22.42 +%s
   22.43 +        </logging:log>
   22.44 +    </SOAP-ENV:Body>
   22.45 +</SOAP-ENV:Envelope>
   22.46 +"""
   22.47 +
   22.48 +class SOAPHandler(logging.Handler):
   22.49 +    """
   22.50 +    A class which sends records to a SOAP server.
   22.51 +    """
   22.52 +    def __init__(self, host, url):
   22.53 +        """
   22.54 +        Initialize the instance with the host and the request URL
   22.55 +        """
   22.56 +        logging.Handler.__init__(self)
   22.57 +        self.host = host
   22.58 +        self.url = url
   22.59 +
   22.60 +    def emit(self, record):
   22.61 +        """
   22.62 +        Send the record to the Web server as a SOAP message
   22.63 +        """
   22.64 +        try:
   22.65 +            import httplib
   22.66 +            h = httplib.HTTP(self.host)
   22.67 +            h.putrequest("POST", self.url)
   22.68 +            keys = record.__dict__.keys()
   22.69 +            keys.sort()
   22.70 +            args = ""
   22.71 +            for key in keys:
   22.72 +                v = record.__dict__[key]
   22.73 +                if type(v) == types.StringType:
   22.74 +                    t = "string"
   22.75 +                elif (type(v) == types.IntType) or (type(v) == types.LongType):
   22.76 +                    t = "integer"
   22.77 +                elif type(v) == types.FloatType:
   22.78 +                    t = "float"
   22.79 +                else:
   22.80 +                    t = "string"
   22.81 +                args = args + "%12s<logging:%s xsi:type=\"xsd:%s\">%s</logging:%s>\n" % ("",
   22.82 +                               key, t, str(v), key)
   22.83 +            data = SOAP_MESSAGE % args[:-1]
   22.84 +            h.putheader("Content-type", "text/plain; charset=\"utf-8\"")
   22.85 +            h.putheader("Content-length", str(len(data)))
   22.86 +            h.endheaders()
   22.87 +            #print data
   22.88 +            h.send(data)
   22.89 +            r = h.getreply()    #can't do anything with the result
   22.90 +            f = h.getfile()
   22.91 +            if f:
   22.92 +                #print f.read()
   22.93 +                f.close()
   22.94 +        except:
   22.95 +            self.handleError(record)
   22.96 +
   22.97 +def main():
   22.98 +    sh = SOAPHandler('localhost:%d' % logging.handlers.DEFAULT_SOAP_LOGGING_PORT, '/log')
   22.99 +    logger = logging.getLogger("log_test13")
  22.100 +    logging.getLogger("").setLevel(logging.DEBUG)
  22.101 +    logger.propagate = 0
  22.102 +    logger.addHandler(sh)
  22.103 +    logger.info("Jackdaws love my big %s of %s", "sphinx", "quartz")
  22.104 +    logger.debug("Pack my %s with five dozen %s", "box", "liquor jugs")
  22.105 +    logger.removeHandler(sh)
  22.106 +
  22.107 +if __name__ == "__main__":
  22.108 +    main()
  22.109 +
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test14.py	Thu Jul 22 13:42:39 2004 +0000
    23.3 @@ -0,0 +1,108 @@
    23.4 +#!/usr/bin/env python
    23.5 +#
    23.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    23.7 +#
    23.8 +# Permission to use, copy, modify, and distribute this software and its
    23.9 +# documentation for any purpose and without fee is hereby granted,
   23.10 +# provided that the above copyright notice appear in all copies and that
   23.11 +# both that copyright notice and this permission notice appear in
   23.12 +# supporting documentation, and that the name of Vinay Sajip
   23.13 +# not be used in advertising or publicity pertaining to distribution
   23.14 +# of the software without specific, written prior permission.
   23.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   23.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   23.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   23.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   23.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   23.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   23.21 +#
   23.22 +# This file is part of the Python logging distribution. See
   23.23 +# http://www.red-dove.com/python_logging.html
   23.24 +#
   23.25 +"""
   23.26 +A test harness for the logging module. An example handler - DBHandler -
   23.27 +which writes to an Python DB API 2.0 data source. You'll need to set this
   23.28 +source up before you run the test.
   23.29 +
   23.30 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   23.31 +"""
   23.32 +import sys, string, time, logging
   23.33 +
   23.34 +class DBHandler(logging.Handler):
   23.35 +    def __init__(self, dsn, uid='', pwd=''):
   23.36 +        logging.Handler.__init__(self)
   23.37 +        import mx.ODBC.Windows
   23.38 +        self.dsn = dsn
   23.39 +        self.uid = uid
   23.40 +        self.pwd = pwd
   23.41 +        self.conn = mx.ODBC.Windows.connect(self.dsn, self.uid, self.pwd)
   23.42 +        self.SQL = """INSERT INTO Events (
   23.43 +                        Created,
   23.44 +                        RelativeCreated,
   23.45 +                        Name,
   23.46 +                        LogLevel,
   23.47 +                        LevelText,
   23.48 +                        Message,
   23.49 +                        Filename,
   23.50 +                        Pathname,
   23.51 +                        Lineno,
   23.52 +                        Milliseconds,
   23.53 +                        Exception,
   23.54 +                        Thread
   23.55 +                   )
   23.56 +                   VALUES (
   23.57 +                        %(dbtime)s,
   23.58 +                        %(relativeCreated)d,
   23.59 +                        '%(name)s',
   23.60 +                        %(levelno)d,
   23.61 +                        '%(levelname)s',
   23.62 +                        '%(message)s',
   23.63 +                        '%(filename)s',
   23.64 +                        '%(pathname)s',
   23.65 +                        %(lineno)d,
   23.66 +                        %(msecs)d,
   23.67 +                        '%(exc_text)s',
   23.68 +                        '%(thread)s'
   23.69 +                   );
   23.70 +                   """
   23.71 +        self.cursor = self.conn.cursor()
   23.72 +
   23.73 +    def formatDBTime(self, record):
   23.74 +        record.dbtime = time.strftime("#%m/%d/%Y#", time.localtime(record.created))
   23.75 +
   23.76 +    def emit(self, record):
   23.77 +        try:
   23.78 +            #use default formatting
   23.79 +            self.format(record)
   23.80 +            #now set the database time up
   23.81 +            self.formatDBTime(record)
   23.82 +            if record.exc_info:
   23.83 +                record.exc_text = logging._defaultFormatter.formatException(record.exc_info)
   23.84 +            else:
   23.85 +                record.exc_text = ""
   23.86 +            sql = self.SQL % record.__dict__
   23.87 +            self.cursor.execute(sql)
   23.88 +            self.conn.commit()
   23.89 +        except:
   23.90 +            import traceback
   23.91 +            ei = sys.exc_info()
   23.92 +            traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
   23.93 +            del ei
   23.94 +
   23.95 +    def close(self):
   23.96 +        self.cursor.close()
   23.97 +        self.conn.close()
   23.98 +        logging.Handler.close(self)
   23.99 +
  23.100 +dh = DBHandler('Logging')
  23.101 +logger = logging.getLogger("")
  23.102 +logger.setLevel(logging.DEBUG)
  23.103 +logger.addHandler(dh)
  23.104 +logger.info("Jackdaws love my big %s of %s", "sphinx", "quartz")
  23.105 +logger.debug("Pack my %s with five dozen %s", "box", "liquor jugs")
  23.106 +try:
  23.107 +    import math
  23.108 +    math.exp(1000)
  23.109 +except:
  23.110 +    logger.exception("Problem with %s", "math.exp")
  23.111 +logging.shutdown()
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test15.py	Thu Jul 22 13:42:39 2004 +0000
    24.3 @@ -0,0 +1,70 @@
    24.4 +#!/usr/bin/env python
    24.5 +#
    24.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    24.7 +#
    24.8 +# Permission to use, copy, modify, and distribute this software and its
    24.9 +# documentation for any purpose and without fee is hereby granted,
   24.10 +# provided that the above copyright notice appear in all copies and that
   24.11 +# both that copyright notice and this permission notice appear in
   24.12 +# supporting documentation, and that the name of Vinay Sajip
   24.13 +# not be used in advertising or publicity pertaining to distribution
   24.14 +# of the software without specific, written prior permission.
   24.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   24.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   24.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   24.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   24.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   24.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   24.21 +#
   24.22 +# This file is part of the Python logging distribution. See
   24.23 +# http://www.red-dove.com/python_logging.html
   24.24 +#
   24.25 +"""
   24.26 +A test harness for the logging module. Tests Filter.
   24.27 +
   24.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   24.29 +"""
   24.30 +
   24.31 +import sys, logging
   24.32 +
   24.33 +FILTER = "a.b"
   24.34 +
   24.35 +def message(s):
   24.36 +    sys.stderr.write("%s\n" % s)
   24.37 +
   24.38 +def doLog():
   24.39 +    logging.getLogger("a").info("Info 1")
   24.40 +    logging.getLogger("a.b").info("Info 2")
   24.41 +    logging.getLogger("a.c").info("Info 3")
   24.42 +    logging.getLogger("a.b.c").info("Info 4")
   24.43 +    logging.getLogger("a.b.c.d").info("Info 5")
   24.44 +    logging.getLogger("a.bb.c").info("Info 6")
   24.45 +    logging.getLogger("b").info("Info 7")
   24.46 +    logging.getLogger("b.a").info("Info 8")
   24.47 +    logging.getLogger("c.a.b").info("Info 9")
   24.48 +    logging.getLogger("a.bb").info("Info 10")
   24.49 +
   24.50 +def test(fs):
   24.51 +    root = logging.getLogger()
   24.52 +    root.setLevel(logging.DEBUG)
   24.53 +    if __name__ == "__main__":
   24.54 +        hand = logging.StreamHandler()
   24.55 +        hand.setFormatter(logging.Formatter("%(name)-10s %(message)s"))
   24.56 +        root.addHandler(hand)
   24.57 +    else:
   24.58 +        hand = root.handlers[0]
   24.59 +    message("Unfiltered...")
   24.60 +    doLog()
   24.61 +    message("Filtered with '%s'..." % fs)
   24.62 +    filt = logging.Filter(fs)
   24.63 +    hand.addFilter(filt)
   24.64 +    doLog()
   24.65 +    hand.removeFilter(filt)
   24.66 +
   24.67 +if __name__ == "__main__":
   24.68 +    import sys
   24.69 +    if len(sys.argv) > 1:
   24.70 +        fs = sys.argv[1]
   24.71 +    else:
   24.72 +        fs = FILTER
   24.73 +    test(fs)
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test16.py	Thu Jul 22 13:42:39 2004 +0000
    25.3 @@ -0,0 +1,73 @@
    25.4 +#!/usr/bin/env python
    25.5 +#
    25.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    25.7 +#
    25.8 +# Permission to use, copy, modify, and distribute this software and its
    25.9 +# documentation for any purpose and without fee is hereby granted,
   25.10 +# provided that the above copyright notice appear in all copies and that
   25.11 +# both that copyright notice and this permission notice appear in
   25.12 +# supporting documentation, and that the name of Vinay Sajip
   25.13 +# not be used in advertising or publicity pertaining to distribution
   25.14 +# of the software without specific, written prior permission.
   25.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   25.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   25.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   25.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   25.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   25.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   25.21 +#
   25.22 +# This file is part of the Python logging distribution. See
   25.23 +# http://www.red-dove.com/python_logging.html
   25.24 +#
   25.25 +"""
   25.26 +A test harness for the logging module. Tests thread safety.
   25.27 +
   25.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   25.29 +"""
   25.30 +
   25.31 +import logging, logging.handlers, thread, threading, random
   25.32 +
   25.33 +logging.raiseExceptions = 1
   25.34 +
   25.35 +NUM_THREADS = 10
   25.36 +LOOP_COUNT = 10000
   25.37 +
   25.38 +LOG_MESSAGES = [
   25.39 +    (logging.DEBUG, "%3d This is a %s message", "debug"),
   25.40 +    (logging.INFO, "%3d This is an %s message", "informational"),
   25.41 +    (logging.WARNING, "%3d This is a %s message", "warning"),
   25.42 +    (logging.ERROR, "%3d This is an %s message", "error"),
   25.43 +    (logging.CRITICAL, "%3d This is a %s message", "critical"),
   25.44 +]
   25.45 +
   25.46 +LOG_NAMES = ["A", "A.B", "A.B.C", "A.B.C.D"]
   25.47 +
   25.48 +def doLog(num):
   25.49 +    logger = logging.getLogger('')
   25.50 +    logger.info("*** thread %s started (%d)", thread.get_ident(), num)
   25.51 +    for i in xrange(LOOP_COUNT):
   25.52 +        logger = logging.getLogger(random.choice(LOG_NAMES))
   25.53 +        a = random.choice(LOG_MESSAGES)
   25.54 +        args = a[0:2] + (num,) + a[2:]
   25.55 +        apply(logger.log, args)
   25.56 +
   25.57 +def test():
   25.58 +    f = logging.Formatter("%(asctime)s %(levelname)-9s %(name)-8s %(thread)5s %(message)s")
   25.59 +    root = logging.getLogger('')
   25.60 +    root.setLevel(logging.DEBUG)
   25.61 +    h = logging.FileHandler('thread.log', 'w')
   25.62 +    root.addHandler(h)
   25.63 +    h.setFormatter(f)
   25.64 +    h = logging.handlers.SocketHandler('localhost', logging.handlers.DEFAULT_TCP_LOGGING_PORT)
   25.65 +    #h = logging.handlers.DatagramHandler('localhost', logging.handlers.DEFAULT_UDP_LOGGING_PORT)
   25.66 +    root.addHandler(h)
   25.67 +    threads = []
   25.68 +    for i in xrange(NUM_THREADS):
   25.69 +        threads.append(threading.Thread(target=doLog, args=(len(threads),)))
   25.70 +    for t in threads:
   25.71 +        t.start()
   25.72 +    for t in threads:
   25.73 +        t.join()
   25.74 +
   25.75 +if __name__ == "__main__":
   25.76 +    test()
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test17.py	Thu Jul 22 13:42:39 2004 +0000
    26.3 @@ -0,0 +1,111 @@
    26.4 +#!/usr/bin/env python
    26.5 +#
    26.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    26.7 +#
    26.8 +# Permission to use, copy, modify, and distribute this software and its
    26.9 +# documentation for any purpose and without fee is hereby granted,
   26.10 +# provided that the above copyright notice appear in all copies and that
   26.11 +# both that copyright notice and this permission notice appear in
   26.12 +# supporting documentation, and that the name of Vinay Sajip
   26.13 +# not be used in advertising or publicity pertaining to distribution
   26.14 +# of the software without specific, written prior permission.
   26.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   26.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   26.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   26.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   26.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   26.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   26.21 +#
   26.22 +# This file is part of the Python logging distribution. See
   26.23 +# http://www.red-dove.com/python_logging.html
   26.24 +#
   26.25 +"""
   26.26 +A test harness for the logging module. Tests thread safety.
   26.27 +
   26.28 +To use as a server, run with no arguments in one process.
   26.29 +To use as a client, run with arguments "-client <filename>" where <filename>
   26.30 +is the name of a file containing a logging configuration.
   26.31 +The example files debug.ini, warn.ini, error.ini and critical.ini are
   26.32 +provided to use in the test. They each have a customized message format
   26.33 +(prefixed with their name) and the loggers have their levels set to the
   26.34 +value implied by their name.
   26.35 +
   26.36 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   26.37 +"""
   26.38 +
   26.39 +import sys, logging, logging.config, thread, threading, random, time, struct
   26.40 +
   26.41 +NUM_THREADS = 10
   26.42 +LOOP_COUNT = 10
   26.43 +
   26.44 +CONFIG_PORT = 9077
   26.45 +
   26.46 +logging.raiseExceptions = 1
   26.47 +
   26.48 +LOG_MESSAGES = [
   26.49 +    (logging.DEBUG, "%3d This is a %s message", "debug"),
   26.50 +    (logging.INFO, "%3d This is an %s message", "informational"),
   26.51 +    (logging.WARNING, "%3d This is a %s message", "warning"),
   26.52 +    (logging.ERROR, "%3d This is an %s message", "error"),
   26.53 +    (logging.CRITICAL, "%3d This is a %s message", "critical"),
   26.54 +]
   26.55 +
   26.56 +LOG_NAMES = ["A", "A.B", "A.B.C", "A.B.C.D"]
   26.57 +
   26.58 +def doLog(num):
   26.59 +    logger = logging.getLogger('')
   26.60 +    logger.setLevel(logging.DEBUG)
   26.61 +    logger.info("*** thread %s started (%d)", thread.get_ident(), num)
   26.62 +    for i in xrange(LOOP_COUNT):
   26.63 +        logger = logging.getLogger(random.choice(LOG_NAMES))
   26.64 +        a = random.choice(LOG_MESSAGES)
   26.65 +        args = a[0:2] + (num,) + a[2:]
   26.66 +        time.sleep(random.random() * 3)
   26.67 +        apply(logger.log, args)
   26.68 +
   26.69 +def runserver():
   26.70 +    f = logging.Formatter("%(asctime)s %(levelname)-9s %(name)-8s %(thread)5s %(message)s")
   26.71 +    root = logging.getLogger('')
   26.72 +    h = logging.StreamHandler()
   26.73 +    root.addHandler(h)
   26.74 +    h.setFormatter(f)
   26.75 +    threads = []
   26.76 +    for i in xrange(NUM_THREADS):
   26.77 +        threads.append(threading.Thread(target=doLog, args=(len(threads),)))
   26.78 +    threads.append(logging.config.listen(CONFIG_PORT))    #don't use default port
   26.79 +    for t in threads:
   26.80 +        t.start()
   26.81 +    for t in threads[:-1]:
   26.82 +        t.join()
   26.83 +    logging.config.stopListening()
   26.84 +    threads[-1].join()
   26.85 +
   26.86 +def runclient(fname):
   26.87 +    import socket
   26.88 +
   26.89 +    print "configuring with '%s'" % fname
   26.90 +    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   26.91 +    sock.connect(('localhost', CONFIG_PORT))
   26.92 +    f = open(fname, "r")
   26.93 +    s = f.read()
   26.94 +    f.close()
   26.95 +    slen = struct.pack(">L", len(s))
   26.96 +    s = slen + s
   26.97 +    sentsofar = 0
   26.98 +    left = len(s)
   26.99 +    while left > 0:
  26.100 +        sent = sock.send(s[sentsofar:])
  26.101 +        sentsofar = sentsofar + sent
  26.102 +        left = left - sent
  26.103 +    sock.close()
  26.104 +
  26.105 +if __name__ == "__main__":
  26.106 +    if "-client" not in sys.argv:
  26.107 +        runserver()
  26.108 +    else:
  26.109 +        sys.argv.remove("-client")
  26.110 +        if len(sys.argv) > 1:
  26.111 +            fname = sys.argv[1]
  26.112 +        else:
  26.113 +            fname = "warn.ini"
  26.114 +        runclient(fname)
  26.115 \ No newline at end of file
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test18.py	Thu Jul 22 13:42:39 2004 +0000
    27.3 @@ -0,0 +1,102 @@
    27.4 +#!/usr/bin/env python
    27.5 +#
    27.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    27.7 +#
    27.8 +# Permission to use, copy, modify, and distribute this software and its
    27.9 +# documentation for any purpose and without fee is hereby granted,
   27.10 +# provided that the above copyright notice appear in all copies and that
   27.11 +# both that copyright notice and this permission notice appear in
   27.12 +# supporting documentation, and that the name of Vinay Sajip
   27.13 +# not be used in advertising or publicity pertaining to distribution
   27.14 +# of the software without specific, written prior permission.
   27.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   27.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   27.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   27.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   27.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   27.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   27.21 +#
   27.22 +# This file is part of the Python logging distribution. See
   27.23 +# http://www.red-dove.com/python_logging.html
   27.24 +#
   27.25 +"""
   27.26 +A test harness for the logging module. Tests MatchFilter.
   27.27 +
   27.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   27.29 +"""
   27.30 +
   27.31 +import logging, types, string
   27.32 +
   27.33 +class MatchFilter(logging.Filter):
   27.34 +    def __init__(self, **kwargs):
   27.35 +        self.dict = kwargs
   27.36 +
   27.37 +    def matchOne(self, key, value, record):
   27.38 +        rv = getattr(record, key)
   27.39 +        if key != "name":
   27.40 +            if key not in ["message", "msg"]:
   27.41 +                return rv == value
   27.42 +            else:
   27.43 +                return string.find(str(rv), value) >= 0
   27.44 +        else:
   27.45 +            if rv == value:
   27.46 +                return 1
   27.47 +            nlen = len(value)
   27.48 +            if string.find(rv, value, 0, nlen) != 0:
   27.49 +                return 0
   27.50 +            if rv[nlen] == ".":
   27.51 +                return 1
   27.52 +
   27.53 +    def matchValue(self, key, record):
   27.54 +        vl = self.dict [key]
   27.55 +        if type(vl) != types.ListType:
   27.56 +            rv = self.matchOne(key, vl, record)
   27.57 +        else:
   27.58 +            for v in vl:
   27.59 +                rv = self.matchOne(key, v, record)
   27.60 +                if rv:
   27.61 +                    break
   27.62 +        return rv
   27.63 +
   27.64 +    def filter(self, record):
   27.65 +        rv = 1
   27.66 +        for k in self.dict.keys():
   27.67 +            if self.matchValue(k, record):
   27.68 +                rv = 0
   27.69 +                break
   27.70 +        return rv
   27.71 +
   27.72 +def doLog(logger, n):
   27.73 +    logger.debug("Debug %d" % n)
   27.74 +    logger.info("Info %d" % n)
   27.75 +    logger.warning("Warning %d" % n)
   27.76 +    logger.error("Error %d" % n)
   27.77 +    logger.critical("Critical %d" % n)
   27.78 +
   27.79 +def test():
   27.80 +    fmt = logging.Formatter("%(name)-10s %(levelname)-9s %(message)s")
   27.81 +    hand = logging.StreamHandler()
   27.82 +    hand.setFormatter(fmt)
   27.83 +    root = logging.getLogger("")
   27.84 +    root.setLevel(logging.DEBUG)
   27.85 +    root.addHandler(hand)
   27.86 +    loggers = ['A',
   27.87 +               'A.B',
   27.88 +               'A.BB',
   27.89 +               'A.C',
   27.90 +               'AA.B',
   27.91 +               'A.B.C',
   27.92 +               'A.B.C.D',
   27.93 +               'A.B.C.D.E',
   27.94 +               'Z.A.B',
   27.95 +              ]
   27.96 +    filt = MatchFilter(name = ['A.C', 'A.B.C'],                 #reject these loggers and their children
   27.97 +                       levelno = [logging.WARNING, logging.CRITICAL],  #reject these levels,
   27.98 +                       msg = 'bug 2'                            #reject if this in message
   27.99 +                      )
  27.100 +    hand.addFilter(filt)
  27.101 +    for log in loggers:
  27.102 +        doLog(logging.getLogger(log), loggers.index(log))
  27.103 +
  27.104 +if __name__ == "__main__":
  27.105 +    test()
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test19.py	Thu Jul 22 13:42:39 2004 +0000
    28.3 @@ -0,0 +1,57 @@
    28.4 +#!/usr/bin/env python
    28.5 +#
    28.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    28.7 +#
    28.8 +# Permission to use, copy, modify, and distribute this software and its
    28.9 +# documentation for any purpose and without fee is hereby granted,
   28.10 +# provided that the above copyright notice appear in all copies and that
   28.11 +# both that copyright notice and this permission notice appear in
   28.12 +# supporting documentation, and that the name of Vinay Sajip
   28.13 +# not be used in advertising or publicity pertaining to distribution
   28.14 +# of the software without specific, written prior permission.
   28.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   28.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   28.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   28.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   28.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   28.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   28.21 +#
   28.22 +# This file is part of the Python logging distribution. See
   28.23 +# http://www.red-dove.com/python_logging.html
   28.24 +#
   28.25 +"""Test harness for the logging module. A basic test of parents.
   28.26 +
   28.27 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   28.28 +"""
   28.29 +
   28.30 +import logging
   28.31 +
   28.32 +def main():
   28.33 +    logging.basicConfig()
   28.34 +    root = logging.getLogger("")
   28.35 +    ab = logging.getLogger("a.b")
   28.36 +    abc = logging.getLogger("a.b.c")
   28.37 +    root.setLevel(logging.ERROR)
   28.38 +    ab.setLevel(logging.INFO)
   28.39 +    abc.info("Info")
   28.40 +    abc.warning("Warning")
   28.41 +    abc.error("Error")
   28.42 +    print "abc = %s" % abc
   28.43 +    print "abc.parent = %s" % abc.parent
   28.44 +    print "ab = %s" % ab
   28.45 +    print "ab.parent = %s" % ab.parent
   28.46 +    print "root = %s" % root
   28.47 +
   28.48 +if __name__ == "__main__":
   28.49 +    import sys
   28.50 +    print sys.argv[0]
   28.51 +    args = sys.argv[1:]
   28.52 +    if "-profile" in args:
   28.53 +        import profile, pstats
   28.54 +        args.remove("-profile")
   28.55 +        statf = "log_test19.pro"
   28.56 +        profile.run("main()", statf)
   28.57 +        stats = pstats.Stats(statf)
   28.58 +        stats.strip_dirs().sort_stats('time').print_stats()
   28.59 +    else:
   28.60 +        main()
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test2.py	Thu Jul 22 13:42:39 2004 +0000
    29.3 @@ -0,0 +1,119 @@
    29.4 +#!/usr/bin/env python
    29.5 +#
    29.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    29.7 +#
    29.8 +# Permission to use, copy, modify, and distribute this software and its
    29.9 +# documentation for any purpose and without fee is hereby granted,
   29.10 +# provided that the above copyright notice appear in all copies and that
   29.11 +# both that copyright notice and this permission notice appear in
   29.12 +# supporting documentation, and that the name of Vinay Sajip
   29.13 +# not be used in advertising or publicity pertaining to distribution
   29.14 +# of the software without specific, written prior permission.
   29.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   29.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   29.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   29.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   29.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   29.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   29.21 +#
   29.22 +# This file is part of the Python logging distribution. See
   29.23 +# http://www.red-dove.com/python_logging.html
   29.24 +#
   29.25 +"""
   29.26 +A test harness for the logging module. Tests logger levels and basic Formatter, and logging to
   29.27 +sockets.
   29.28 +
   29.29 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   29.30 +"""
   29.31 +
   29.32 +import logging, logging.handlers, socket
   29.33 +
   29.34 +msgcount = 0
   29.35 +
   29.36 +def nextmessage():
   29.37 +    global msgcount
   29.38 +    rv = "Message %d" % msgcount
   29.39 +    msgcount = msgcount + 1
   29.40 +    return rv
   29.41 +
   29.42 +def main():
   29.43 +    logging.basicConfig()
   29.44 +    logging.getLogger("").setLevel(logging.DEBUG)
   29.45 +    hdlr = logging.handlers.SocketHandler('localhost', logging.handlers.DEFAULT_TCP_LOGGING_PORT)
   29.46 +    if __name__ == "__main__":
   29.47 +        hdlr.setFormatter(logging.Formatter("%(asctime)s %(name)-19s %(levelname)-5s - %(message)s"))
   29.48 +    logging.getLogger("").addHandler(hdlr)
   29.49 +    ERR = logging.getLogger("ERR")
   29.50 +    ERR.setLevel(logging.ERROR)
   29.51 +    INF = logging.getLogger("INF")
   29.52 +    INF.setLevel(logging.INFO)
   29.53 +    INF_ERR  = logging.getLogger("INF.ERR")
   29.54 +    INF_ERR.setLevel(logging.ERROR)
   29.55 +    DEB = logging.getLogger("DEB")
   29.56 +    DEB.setLevel(logging.DEBUG)
   29.57 +
   29.58 +    INF_UNDEF = logging.getLogger("INF.UNDEF")
   29.59 +    INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
   29.60 +    UNDEF = logging.getLogger("UNDEF")
   29.61 +
   29.62 +    GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
   29.63 +    CHILD = logging.getLogger("INF.BADPARENT")
   29.64 +
   29.65 +    #These should log
   29.66 +    ERR.log(logging.CRITICAL, nextmessage())
   29.67 +    ERR.error(nextmessage())
   29.68 +
   29.69 +    INF.log(logging.CRITICAL, nextmessage())
   29.70 +    INF.error(nextmessage())
   29.71 +    INF.warning(nextmessage())
   29.72 +    INF.info(nextmessage())
   29.73 +
   29.74 +    INF_UNDEF.log(logging.CRITICAL, nextmessage())
   29.75 +    INF_UNDEF.error(nextmessage())
   29.76 +    INF_UNDEF.warning(nextmessage())
   29.77 +    INF_UNDEF.info(nextmessage())
   29.78 +
   29.79 +    INF_ERR.log(logging.CRITICAL, nextmessage())
   29.80 +    INF_ERR.error(nextmessage())
   29.81 +
   29.82 +    INF_ERR_UNDEF.log(logging.CRITICAL, nextmessage())
   29.83 +    INF_ERR_UNDEF.error(nextmessage())
   29.84 +
   29.85 +    DEB.log(logging.CRITICAL, nextmessage())
   29.86 +    DEB.error(nextmessage())
   29.87 +    DEB.warning(nextmessage())
   29.88 +    DEB.info(nextmessage())
   29.89 +    DEB.debug(nextmessage())
   29.90 +
   29.91 +    UNDEF.log(logging.CRITICAL, nextmessage())
   29.92 +    UNDEF.error(nextmessage())
   29.93 +    UNDEF.warning(nextmessage())
   29.94 +    UNDEF.info(nextmessage())
   29.95 +
   29.96 +    GRANDCHILD.log(logging.CRITICAL, nextmessage())
   29.97 +    CHILD.log(logging.CRITICAL, nextmessage())
   29.98 +
   29.99 +    #These should not log
  29.100 +    ERR.warning(nextmessage())
  29.101 +    ERR.info(nextmessage())
  29.102 +    ERR.debug(nextmessage())
  29.103 +
  29.104 +    INF.debug(nextmessage())
  29.105 +    INF_UNDEF.debug(nextmessage())
  29.106 +
  29.107 +    INF_ERR.warning(nextmessage())
  29.108 +    INF_ERR.info(nextmessage())
  29.109 +    INF_ERR.debug(nextmessage())
  29.110 +    INF_ERR_UNDEF.warning(nextmessage())
  29.111 +    INF_ERR_UNDEF.info(nextmessage())
  29.112 +    INF_ERR_UNDEF.debug(nextmessage())
  29.113 +
  29.114 +    INF.info("Messages should bear numbers 0 through 24.")
  29.115 +    hdlr.close()
  29.116 +    logging.getLogger("").removeHandler(hdlr)
  29.117 +
  29.118 +if __name__ == "__main__":
  29.119 +    try:
  29.120 +        main()
  29.121 +    except socket.error:
  29.122 +        print "\nA socket error occurred. Ensure that logrecv.py is running to receive logging requests from this script."
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test20.py	Thu Jul 22 13:42:39 2004 +0000
    30.3 @@ -0,0 +1,84 @@
    30.4 +#!/usr/bin/env python
    30.5 +#
    30.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    30.7 +#
    30.8 +# Permission to use, copy, modify, and distribute this software and its
    30.9 +# documentation for any purpose and without fee is hereby granted,
   30.10 +# provided that the above copyright notice appear in all copies and that
   30.11 +# both that copyright notice and this permission notice appear in
   30.12 +# supporting documentation, and that the name of Vinay Sajip
   30.13 +# not be used in advertising or publicity pertaining to distribution
   30.14 +# of the software without specific, written prior permission.
   30.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   30.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   30.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   30.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   30.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   30.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   30.21 +#
   30.22 +# This file is part of the Python logging distribution. See
   30.23 +# http://www.red-dove.com/python_logging.html
   30.24 +#
   30.25 +"""Test harness for the logging module. Demonstrates the use of custom class
   30.26 +instances for messages and filtering based on classes.
   30.27 +
   30.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   30.29 +"""
   30.30 +
   30.31 +import logging
   30.32 +
   30.33 +class MyClass:
   30.34 +    def __init__(self, arg1, arg2):
   30.35 +        self.arg1 = arg1
   30.36 +        self.arg2 = arg2
   30.37 +
   30.38 +    def __str__(self):
   30.39 +        return "%s, %s" % (self.arg1, self.arg2)
   30.40 +
   30.41 +class MyChildClass(MyClass):
   30.42 +    pass
   30.43 +
   30.44 +class ClassFilter(logging.Filter):
   30.45 +    def __init__(self, klass):
   30.46 +        self.klass = klass
   30.47 +
   30.48 +    def filter(self, record):
   30.49 +        return isinstance(record.msg, self.klass)
   30.50 +
   30.51 +class MyClassFilter(ClassFilter):
   30.52 +    def __init__(self, arg):
   30.53 +        ClassFilter.__init__(self, MyClass)
   30.54 +        self.arg = arg
   30.55 +
   30.56 +    def filter(self, record):
   30.57 +        return ClassFilter.filter(self, record) and (record.msg.arg2 == self.arg)
   30.58 +
   30.59 +def main():
   30.60 +    handler = logging.StreamHandler()
   30.61 +    root = logging.getLogger("")
   30.62 +    root.setLevel(logging.DEBUG)
   30.63 +    root.addHandler(handler)
   30.64 +    root.addFilter(MyClassFilter("world"))
   30.65 +    #Not logged, as it's not a MyClass instance
   30.66 +    root.info("%s, %s", "Hello", "world")
   30.67 +    #Logged, as it's an appropriate instance which matches the filter criteria
   30.68 +    root.info(MyClass("Hello", "world"))
   30.69 +    #Not logged, as it's an appropriate class but doesn't match the filter criteria
   30.70 +    root.info(MyClass("Hello", "world!"))
   30.71 +    #Logged, as it's an appropriate instance which matches the filter criteria
   30.72 +    root.info(MyClass("Goodbye", "world"))
   30.73 +    #Logged, as it's an appropriate class which matches the filter criteria
   30.74 +    root.info(MyChildClass("Hello again", "world"))
   30.75 +
   30.76 +if __name__ == "__main__":
   30.77 +    import sys
   30.78 +    args = sys.argv[1:]
   30.79 +    if "-profile" in args:
   30.80 +        import profile, pstats
   30.81 +        args.remove("-profile")
   30.82 +        statf = "log_test20.pro"
   30.83 +        profile.run("main()", statf)
   30.84 +        stats = pstats.Stats(statf)
   30.85 +        stats.strip_dirs().sort_stats('time').print_stats()
   30.86 +    else:
   30.87 +        main()
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test21.py	Thu Jul 22 13:42:39 2004 +0000
    31.3 @@ -0,0 +1,141 @@
    31.4 +#!/usr/bin/env python
    31.5 +#
    31.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    31.7 +#
    31.8 +# Permission to use, copy, modify, and distribute this software and its
    31.9 +# documentation for any purpose and without fee is hereby granted,
   31.10 +# provided that the above copyright notice appear in all copies and that
   31.11 +# both that copyright notice and this permission notice appear in
   31.12 +# supporting documentation, and that the name of Vinay Sajip
   31.13 +# not be used in advertising or publicity pertaining to distribution
   31.14 +# of the software without specific, written prior permission.
   31.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   31.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   31.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   31.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   31.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   31.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   31.21 +#
   31.22 +# This file is part of the Python logging distribution. See
   31.23 +# http://www.red-dove.com/python_logging.html
   31.24 +#
   31.25 +"""Test harness for the logging module. Demonstrates the use of a wildcard
   31.26 +name-space filter with and without custom message classes.
   31.27 +
   31.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   31.29 +"""
   31.30 +
   31.31 +import logging, re, string, types
   31.32 +
   31.33 +class TaggedEvent:
   31.34 +    def __init__(self, tag, msg):
   31.35 +        self.tag = tag
   31.36 +        self.msg = msg
   31.37 +
   31.38 +    def __str__(self):
   31.39 +        return "%s: %s" % (self.tag, self.msg)
   31.40 +
   31.41 +class WildcardFilter(logging.Filter):
   31.42 +    def __init__(self, wildcards):
   31.43 +        self.setWildcards(wildcards)
   31.44 +
   31.45 +    def setWildcard(self, wildcard):
   31.46 +        arr = string.split(wildcard, ".")
   31.47 +        for i in xrange(len(arr)):
   31.48 +            s = arr[i]
   31.49 +            if s == "*":
   31.50 +                arr[i] = r'[\w.]*'
   31.51 +            elif string.find(s, "*") > 0:
   31.52 +                arr[i] = string.replace(s, "*", r'[\w]*')
   31.53 +        s = "^%s$" % string.join(arr, r'\.')
   31.54 +        self.patterns.append(re.compile(s))
   31.55 +
   31.56 +    def setWildcards(self, wildcards):
   31.57 +        if type(wildcards) != types.ListType:
   31.58 +            wildcards = [wildcards]
   31.59 +        self.patterns = []
   31.60 +        for wildcard in wildcards:
   31.61 +            self.setWildcard(wildcard)
   31.62 +
   31.63 +    def filter(self, record):
   31.64 +        rv = 0
   31.65 +        for pat in self.patterns:
   31.66 +            m = pat.match(record.name)
   31.67 +            if m is not None:
   31.68 +                rv = 1
   31.69 +                break
   31.70 +        return rv
   31.71 +
   31.72 +class TagFilter(WildcardFilter):
   31.73 +    def filter(self, record):
   31.74 +        rv = 0
   31.75 +        if isinstance(record.msg, TaggedEvent):
   31.76 +            tag = record.msg.tag
   31.77 +        else:
   31.78 +            tag = record.name
   31.79 +        for pat in self.patterns:
   31.80 +            m = pat.match(tag)
   31.81 +            if m is not None:
   31.82 +                rv = 1
   31.83 +                break
   31.84 +        return rv
   31.85 +
   31.86 +def main():
   31.87 +    handler = logging.StreamHandler()
   31.88 +    root = logging.getLogger("")
   31.89 +    root.setLevel(logging.DEBUG)
   31.90 +    ab = logging.getLogger("a.b")
   31.91 +    abc = logging.getLogger("a.b.c")
   31.92 +
   31.93 +    root.addHandler(handler)
   31.94 +    filter = WildcardFilter("*.b")
   31.95 +    handler.addFilter(filter)
   31.96 +
   31.97 +    ab.info("#1 from a.b")       #logged
   31.98 +    abc.info("#1 from a.b.c")    #not logged
   31.99 +    filter.setWildcards("*.b.c")
  31.100 +    ab.info("#2 from a.b")       #not logged
  31.101 +    abc.info("#2 from a.b.c")    #logged
  31.102 +    filter.setWildcards("*.b*")
  31.103 +    ab.info("#3 from a.b")       #logged
  31.104 +    abc.info("#3 from a.b.c")    #not logged
  31.105 +    filter.setWildcards("*")
  31.106 +    ab.info("#4 from a.b")       #logged
  31.107 +    abc.info("#4 from a.b.c")    #logged
  31.108 +    filter.setWildcards("a*")
  31.109 +    ab.info("#5 from a.b")       #not logged
  31.110 +    abc.info("#5 from a.b.c")    #not logged
  31.111 +    filter.setWildcards("a.*")
  31.112 +    ab.info("#6 from a.b")       #logged
  31.113 +    abc.info("#6 from a.b.c")    #logged
  31.114 +    filter.setWildcards("*.b.*")
  31.115 +    ab.info("#7 from a.b")       #not logged
  31.116 +    abc.info("#7 from a.b.c")    #logged
  31.117 +    filter.setWildcards(["*.b", "*.b.*"])
  31.118 +    ab.info("#8 from a.b")       #logged
  31.119 +    abc.info("#8 from a.b.c")    #logged
  31.120 +    filter.setWildcards(["a.*.c"])
  31.121 +    ab.info("#9 from a.b")       #not logged
  31.122 +    abc.info("#9 from a.b.c")    #logged
  31.123 +
  31.124 +    #Now test filtering with a tagged class
  31.125 +    handler.removeFilter(filter)
  31.126 +    tagfilter = TagFilter(["*.b", "*.b.*"])
  31.127 +    root.addFilter(tagfilter)
  31.128 +    root.info(TaggedEvent("a.b", "#10"))     #logged
  31.129 +    root.info(TaggedEvent("a.c", "#10"))     #not logged
  31.130 +    root.info(TaggedEvent("a.b.c", "#10"))   #logged
  31.131 +    root.info(TaggedEvent("a.b.d", "#10"))   #logged
  31.132 +
  31.133 +if __name__ == "__main__":
  31.134 +    import sys
  31.135 +    args = sys.argv[1:]
  31.136 +    if "-profile" in args:
  31.137 +        import profile, pstats
  31.138 +        args.remove("-profile")
  31.139 +        statf = "log_test21.pro"
  31.140 +        profile.run("main()", statf)
  31.141 +        stats = pstats.Stats(statf)
  31.142 +        stats.strip_dirs().sort_stats('time').print_stats()
  31.143 +    else:
  31.144 +        main()
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test22.py	Thu Jul 22 13:42:39 2004 +0000
    32.3 @@ -0,0 +1,50 @@
    32.4 +#!/usr/bin/env python
    32.5 +#
    32.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    32.7 +#
    32.8 +# Permission to use, copy, modify, and distribute this software and its
    32.9 +# documentation for any purpose and without fee is hereby granted,
   32.10 +# provided that the above copyright notice appear in all copies and that
   32.11 +# both that copyright notice and this permission notice appear in
   32.12 +# supporting documentation, and that the name of Vinay Sajip
   32.13 +# not be used in advertising or publicity pertaining to distribution
   32.14 +# of the software without specific, written prior permission.
   32.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   32.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   32.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   32.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   32.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   32.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   32.21 +#
   32.22 +# This file is part of the Python logging distribution. See
   32.23 +# http://www.red-dove.com/python_logging.html
   32.24 +#
   32.25 +"""Test harness for the logging module. Demonstrates the use of different
   32.26 +converters for time(secs) -> time(tuple).
   32.27 +
   32.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   32.29 +"""
   32.30 +
   32.31 +import logging, time
   32.32 +
   32.33 +def main():
   32.34 +    handler = logging.StreamHandler()
   32.35 +    f1 = logging.Formatter("%(asctime)s %(message)s", "%m/%d %H:%M:%S")
   32.36 +    f2 = logging.Formatter("%(asctime)s %(message)s", "%m/%d %H:%M:%S")
   32.37 +    f2.converter = time.gmtime
   32.38 +    handler.setFormatter(f1)
   32.39 +    root = logging.getLogger("")
   32.40 +    root.setLevel(logging.DEBUG)
   32.41 +    root.addHandler(handler)
   32.42 +    root.info("Something happened! [should be in local time]")
   32.43 +    handler.setFormatter(f2)
   32.44 +    root.info("Something else happened! [should be in GMT]")
   32.45 +    handler.setFormatter(f1)
   32.46 +    root.info("Something happened again! [should be in local time]")
   32.47 +    logging.Formatter.converter = time.gmtime
   32.48 +    root.info("Something else happened again! [should be in GMT]")
   32.49 +    logging.Formatter.converter = time.localtime
   32.50 +    root.info("Something else happened yet again! [should be in local time]")
   32.51 +
   32.52 +if __name__ == "__main__":
   32.53 +    main()
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test3.ini	Thu Jul 22 13:42:39 2004 +0000
    33.3 @@ -0,0 +1,95 @@
    33.4 +[loggers]
    33.5 +keys=root,area1,area11,area111,area1111,area11111,area111111
    33.6 +
    33.7 +[handlers]
    33.8 +keys=console,file,socket,datagram,syslog,NT,SMTP
    33.9 +
   33.10 +[formatters]
   33.11 +keys=short,medium,long
   33.12 +
   33.13 +[logger_root]
   33.14 +handlers=console
   33.15 +level=DEBUG
   33.16 +
   33.17 +[logger_area1]
   33.18 +level=DEBUG
   33.19 +qualname=log02
   33.20 +handlers=file
   33.21 +
   33.22 +[logger_area11]
   33.23 +level=INFO
   33.24 +qualname=log02.log03
   33.25 +handlers=socket
   33.26 +
   33.27 +[logger_area111]
   33.28 +level=WARN
   33.29 +propagate=0
   33.30 +qualname=log02.log03.log04
   33.31 +handlers=datagram
   33.32 +
   33.33 +[logger_area1111]
   33.34 +level=ERROR
   33.35 +qualname=log02.log03.log04.log05
   33.36 +handlers=syslog
   33.37 +
   33.38 +[logger_area11111]
   33.39 +level=CRITICAL
   33.40 +qualname=log02.log03.log04.log05.log06
   33.41 +handlers=NT
   33.42 +
   33.43 +[logger_area111111]
   33.44 +level=WARN
   33.45 +qualname=log02.log03.log04.log05.log06.log07
   33.46 +handlers=SMTP
   33.47 +
   33.48 +[handler_console]
   33.49 +class=StreamHandler
   33.50 +formatter=medium
   33.51 +stream=sys.stdout
   33.52 +args=(sys.stdout,)
   33.53 +
   33.54 +[handler_file]
   33.55 +class=FileHandler
   33.56 +level=DEBUG
   33.57 +formatter=long
   33.58 +args=('python.log', 'w')
   33.59 +
   33.60 +[handler_socket]
   33.61 +class=handlers.SocketHandler
   33.62 +level=INFO
   33.63 +formatter=medium
   33.64 +args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)
   33.65 +
   33.66 +[handler_datagram]
   33.67 +class=handlers.DatagramHandler
   33.68 +level=WARN
   33.69 +formatter=medium
   33.70 +args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)
   33.71 +
   33.72 +[handler_syslog]
   33.73 +class=handlers.SysLogHandler
   33.74 +level=ERROR
   33.75 +formatter=short
   33.76 +args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
   33.77 +
   33.78 +[handler_NT]
   33.79 +class=handlers.NTEventLogHandler
   33.80 +level=CRITICAL
   33.81 +formatter=medium
   33.82 +args=('Python Application', '', 'Application')
   33.83 +
   33.84 +[handler_SMTP]
   33.85 +class=handlers.SMTPHandler
   33.86 +level=WARN
   33.87 +formatter=long
   33.88 +args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
   33.89 +
   33.90 +[formatter_short]
   33.91 +format=%(message)s
   33.92 +
   33.93 +[formatter_long]
   33.94 +format=%(asctime)s %(pathname)s(%(lineno)d): %(levelname)s %(message)s
   33.95 +
   33.96 +[formatter_medium]
   33.97 +format=%(asctime)s %(levelname)s %(message)s
   33.98 +datefmt=%m-%d-%Y
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test3.py	Thu Jul 22 13:42:39 2004 +0000
    34.3 @@ -0,0 +1,70 @@
    34.4 +#!/usr/bin/env python
    34.5 +#
    34.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    34.7 +#
    34.8 +# Permission to use, copy, modify, and distribute this software and its
    34.9 +# documentation for any purpose and without fee is hereby granted,
   34.10 +# provided that the above copyright notice appear in all copies and that
   34.11 +# both that copyright notice and this permission notice appear in
   34.12 +# supporting documentation, and that the name of Vinay Sajip
   34.13 +# not be used in advertising or publicity pertaining to distribution
   34.14 +# of the software without specific, written prior permission.
   34.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   34.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   34.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   34.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   34.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   34.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   34.21 +#
   34.22 +# This file is part of the Python logging distribution. See
   34.23 +# http://www.red-dove.com/python_logging.html
   34.24 +#
   34.25 +"""
   34.26 +A test harness for the logging module. Tests new fileConfig (not yet a complete test).
   34.27 +
   34.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   34.29 +"""
   34.30 +import logging, logging.config
   34.31 +
   34.32 +def doLog(logger):
   34.33 +    logger.debug("Debug")
   34.34 +    logger.info("Info")
   34.35 +    logger.warning("Warning")
   34.36 +    logger.error("Error")
   34.37 +    logger.critical("Critical")
   34.38 +
   34.39 +def main():
   34.40 +    logging.config.fileConfig("log_test3.ini")
   34.41 +    logger = logging.getLogger(None)
   34.42 +    print "---------------------------------------------------"
   34.43 +    print "-- Logging to root; messages appear on console only"
   34.44 +    print "---------------------------------------------------"
   34.45 +    doLog(logger)
   34.46 +    print "----------------------------------------------------------------------"
   34.47 +    print "-- Logging to log02; messages appear on console and in file python.log"
   34.48 +    print "----------------------------------------------------------------------"
   34.49 +    logger = logging.getLogger("log02")
   34.50 +    doLog(logger)
   34.51 +    print "--------------------------------------------------------------------------"
   34.52 +    print "-- Logging to log02.log03; messages appear on console, in file python.log,"
   34.53 +    print "-- and at logrecv.py tcp (if running. <= DEBUG messages will not appear)."
   34.54 +    print "--------------------------------------------------------------------------"
   34.55 +    logger = logging.getLogger("log02.log03")
   34.56 +    doLog(logger)
   34.57 +    print "-----------------------------------------------------------------------"
   34.58 +    print "-- Logging to log02.log03.log04; messages appear only at logrecv.py udp"
   34.59 +    print "-- (if running. <= INFO messages will not appear)."
   34.60 +    print "-----------------------------------------------------------------------"
   34.61 +    logger = logging.getLogger("log02.log03.log04")
   34.62 +    doLog(logger)
   34.63 +    print "--------------------------------------------------------------------"
   34.64 +    print "-- Logging to log02.log03.log04.log05.log06; messages appear at"
   34.65 +    print "-- logrecv.py udp (if running. < CRITICAL messages will not appear)."
   34.66 +    print "--------------------------------------------------------------------"
   34.67 +    logger = logging.getLogger("log02.log03.log04.log05.log06")
   34.68 +    doLog(logger)
   34.69 +    print "-- All done."
   34.70 +    logging.shutdown()
   34.71 +
   34.72 +if __name__ == "__main__":
   34.73 +    main()
   34.74 \ No newline at end of file
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test4.py	Thu Jul 22 13:42:39 2004 +0000
    35.3 @@ -0,0 +1,168 @@
    35.4 +#!/usr/bin/env python
    35.5 +#
    35.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    35.7 +#
    35.8 +# Permission to use, copy, modify, and distribute this software and its
    35.9 +# documentation for any purpose and without fee is hereby granted,
   35.10 +# provided that the above copyright notice appear in all copies and that
   35.11 +# both that copyright notice and this permission notice appear in
   35.12 +# supporting documentation, and that the name of Vinay Sajip
   35.13 +# not be used in advertising or publicity pertaining to distribution
   35.14 +# of the software without specific, written prior permission.
   35.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   35.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   35.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   35.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   35.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   35.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   35.21 +#
   35.22 +# This file is part of the Python logging distribution. See
   35.23 +# http://www.red-dove.com/python_logging.html
   35.24 +#
   35.25 +"""
   35.26 +A test harness for the logging module. Tests arbitrary logging levels, filtering, and
   35.27 +use of strftime formatting.
   35.28 +
   35.29 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   35.30 +"""
   35.31 +
   35.32 +import logging
   35.33 +import locale, sys
   35.34 +
   35.35 +locale.setlocale(locale.LC_ALL, '')
   35.36 +
   35.37 +def message(s):
   35.38 +    sys.stderr.write("%s\n" % s)
   35.39 +
   35.40 +#
   35.41 +#   First, we define our levels. There can be as many as you want - the only limitations are that
   35.42 +#   they should be integers, the lowest should be > 0 and larger values mean less information being
   35.43 +#   logged. If you need specific level values which do not fit into these limitations, you can use
   35.44 +#   a mapping dictionary to convert between your application levels and the logging system.
   35.45 +#
   35.46 +SILENT      = 10
   35.47 +TACITURN    = 9
   35.48 +TERSE       = 8
   35.49 +EFFUSIVE    = 7
   35.50 +SOCIABLE    = 6
   35.51 +VERBOSE     = 5
   35.52 +TALKATIVE   = 4
   35.53 +GARRULOUS   = 3
   35.54 +CHATTERBOX  = 2
   35.55 +BORING      = 1
   35.56 +
   35.57 +LEVEL_RANGE = range(BORING, SILENT + 1)
   35.58 +
   35.59 +#
   35.60 +#   Next, we define names for our levels. You don't need to do this - in which case the system will
   35.61 +#   use "Level n" to denote the text for the level.
   35.62 +#
   35.63 +my_logging_levels = {
   35.64 +    SILENT      : 'Silent',
   35.65 +    TACITURN    : 'Taciturn',
   35.66 +    TERSE           : 'Terse',
   35.67 +    EFFUSIVE    : 'Effusive',
   35.68 +    SOCIABLE    : 'Sociable',
   35.69 +    VERBOSE     :   'Verbose',
   35.70 +    TALKATIVE   :   'Talkative',
   35.71 +    GARRULOUS   :   'Garrulous',
   35.72 +    CHATTERBOX: 'Chatterbox',
   35.73 +    BORING      :   'Boring',
   35.74 +}
   35.75 +
   35.76 +#
   35.77 +#   Now, tell the logging system to associate names with our levels.
   35.78 +#
   35.79 +for lvl in my_logging_levels.keys():
   35.80 +    logging.addLevelName(lvl, my_logging_levels[lvl])
   35.81 +
   35.82 +#
   35.83 +#   Now, define a test function which logs an event at each of our levels.
   35.84 +#
   35.85 +def doLog(log):
   35.86 +    for lvl in LEVEL_RANGE:
   35.87 +        log.log(lvl, "This should only be seen at the '%s' logging level (or lower)", logging.getLevelName(lvl))
   35.88 +
   35.89 +#
   35.90 +#   Get the root logger and add a console hander to it, when run as a script.
   35.91 +#
   35.92 +log = logging.getLogger("")
   35.93 +
   35.94 +if __name__ == "__main__":
   35.95 +    hdlr = logging.StreamHandler()
   35.96 +    hdlr.setFormatter(logging.Formatter("%(asctime)s %(message)s", "%X")) #date format is as per the locale
   35.97 +    log.addHandler(hdlr)
   35.98 +else:
   35.99 +    hdlr = log.handlers[0]
  35.100 +#
  35.101 +#   Set the logging level to each different value and call the utility function to log events.
  35.102 +#   In the output, you should see that each time round the loop, the logging events actually output
  35.103 +#   decreases.
  35.104 +#
  35.105 +for lvl in LEVEL_RANGE:
  35.106 +    message("-- setting logging level to '%s' -----" % logging.getLevelName(lvl))
  35.107 +    log.setLevel(lvl)
  35.108 +    doLog(log)
  35.109 +#
  35.110 +#   Now, we demonstrate level filtering at the handler level. Tell the handler defined above
  35.111 +#   to filter at level 'SOCIABLE', and repeat the above loop. Compare the output from the two runs.
  35.112 +#
  35.113 +hdlr.setLevel(SOCIABLE)
  35.114 +message("-- Filtering at handler level to SOCIABLE --")
  35.115 +for lvl in LEVEL_RANGE:
  35.116 +    message("-- setting logging level to '%s' -----" % logging.getLevelName(lvl))
  35.117 +    log.setLevel(lvl)
  35.118 +    doLog(log)
  35.119 +
  35.120 +hdlr.setLevel(0)    #turn off level filtering at the handler
  35.121 +
  35.122 +#
  35.123 +#   Now, let's demonstrate filtering. Suppose for some perverse reason we only want to print out
  35.124 +#   all except GARRULOUS messages. Let's create a filter for this purpose...
  35.125 +#
  35.126 +class SpecificLevelFilter(logging.Filter):
  35.127 +    def __init__(self, lvl):
  35.128 +        self.level = lvl
  35.129 +
  35.130 +    def filter(self, record):
  35.131 +        return self.level != record.levelno
  35.132 +
  35.133 +class GarrulousFilter(SpecificLevelFilter):
  35.134 +    def __init__(self):
  35.135 +        SpecificLevelFilter.__init__(self, GARRULOUS)
  35.136 +
  35.137 +garr = GarrulousFilter()
  35.138 +hdlr.addFilter(garr)
  35.139 +message("-- Filtering using GARRULOUS filter --")
  35.140 +for lvl in LEVEL_RANGE:
  35.141 +    message("-- setting logging level to '%s' -----" % logging.getLevelName(lvl))
  35.142 +    log.setLevel(lvl)
  35.143 +    doLog(log)
  35.144 +#
  35.145 +#   Now, let's demonstrate filtering at the logger. This time, use a filter which excludes SOCIABLE
  35.146 +#   and TACITURN messages. Note that GARRULOUS events are still excluded.
  35.147 +#
  35.148 +class VerySpecificFilter(logging.Filter):
  35.149 +    def filter(self, record):
  35.150 +        return record.levelno not in [SOCIABLE, TACITURN]
  35.151 +
  35.152 +spec = VerySpecificFilter()
  35.153 +log.addFilter(spec)
  35.154 +message("-- Filtering using specific filter for SOCIABLE, TACITURN --")
  35.155 +for lvl in LEVEL_RANGE:
  35.156 +    message("-- setting logging level to '%s' -----" % logging.getLevelName(lvl))
  35.157 +    log.setLevel(lvl)
  35.158 +    doLog(log)
  35.159 +
  35.160 +log.removeFilter(spec)
  35.161 +hdlr.removeFilter(garr)
  35.162 +#Undo the one level which clashes...for regression tests
  35.163 +logging.addLevelName(logging.DEBUG, "DEBUG")
  35.164 +
  35.165 +#
  35.166 +#   Er...that's it for now
  35.167 +#
  35.168 +if __name__ == "__main__":
  35.169 +    print "All done."
  35.170 +    logging.shutdown()
  35.171 +
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test5.py	Thu Jul 22 13:42:39 2004 +0000
    36.3 @@ -0,0 +1,44 @@
    36.4 +#!/usr/bin/env python
    36.5 +#
    36.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    36.7 +#
    36.8 +# Permission to use, copy, modify, and distribute this software and its
    36.9 +# documentation for any purpose and without fee is hereby granted,
   36.10 +# provided that the above copyright notice appear in all copies and that
   36.11 +# both that copyright notice and this permission notice appear in
   36.12 +# supporting documentation, and that the name of Vinay Sajip
   36.13 +# not be used in advertising or publicity pertaining to distribution
   36.14 +# of the software without specific, written prior permission.
   36.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   36.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   36.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   36.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   36.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   36.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   36.21 +#
   36.22 +# This file is part of the Python logging distribution. See
   36.23 +# http://www.red-dove.com/python_logging.html
   36.24 +#
   36.25 +"""
   36.26 +A test harness for the logging module. Tests SMTPHandler.
   36.27 +
   36.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   36.29 +"""
   36.30 +import logging, logging.handlers
   36.31 +
   36.32 +MAILHOST = 'beta'
   36.33 +FROM     = 'log_test5@yourdomain.com'
   36.34 +TO       = ['arkadi_renko']
   36.35 +SUBJECT  = 'Test Logging email from Python logging module (non-buffering)'
   36.36 +
   36.37 +def main():
   36.38 +    log = logging.getLogger("")
   36.39 +    log.setLevel(logging.DEBUG)
   36.40 +    hdlr = logging.handlers.SMTPHandler(MAILHOST, FROM, TO, SUBJECT)
   36.41 +    hdlr.setFormatter(logging.Formatter("%(asctime)s %(levelname)-5s %(message)s"))
   36.42 +    log.addHandler(hdlr)
   36.43 +    log.info("Test email contents")
   36.44 +    log.removeHandler(hdlr)
   36.45 +
   36.46 +if __name__ == "__main__":
   36.47 +    main()
   36.48 \ No newline at end of file
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test6.py	Thu Jul 22 13:42:39 2004 +0000
    37.3 @@ -0,0 +1,47 @@
    37.4 +#!/usr/bin/env python
    37.5 +#
    37.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    37.7 +#
    37.8 +# Permission to use, copy, modify, and distribute this software and its
    37.9 +# documentation for any purpose and without fee is hereby granted,
   37.10 +# provided that the above copyright notice appear in all copies and that
   37.11 +# both that copyright notice and this permission notice appear in
   37.12 +# supporting documentation, and that the name of Vinay Sajip
   37.13 +# not be used in advertising or publicity pertaining to distribution
   37.14 +# of the software without specific, written prior permission.
   37.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   37.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   37.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   37.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   37.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   37.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   37.21 +#
   37.22 +# This file is part of the Python logging distribution. See
   37.23 +# http://www.red-dove.com/python_logging.html
   37.24 +#
   37.25 +"""
   37.26 +A test harness for the logging module. Tests NTEventLogHandler.
   37.27 +
   37.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   37.29 +"""
   37.30 +import logging, logging.handlers
   37.31 +
   37.32 +def main():
   37.33 +    ntl = logging.handlers.NTEventLogHandler("Python Logging Test")
   37.34 +    logger = logging.getLogger("")
   37.35 +    logger.setLevel(logging.DEBUG)
   37.36 +    logger.addHandler(ntl)
   37.37 +    logger.debug("This is a '%s' message", "Debug")
   37.38 +    logger.info("This is a '%s' message", "Info")
   37.39 +    logger.warning("This is a '%s' message", "Warning")
   37.40 +    logger.error("This is a '%s' message", "Error")
   37.41 +    logger.critical("This is a '%s' message", "Critical")
   37.42 +    try:
   37.43 +        x = 4 / 0
   37.44 +    except:
   37.45 +        logger.info("This is an %s (or should that be %s?)", "informational exception", "exceptional information", exc_info=1)
   37.46 +        logger.exception("This is the same stuff, via a %s", "exception() call")
   37.47 +    logger.removeHandler(ntl)
   37.48 +
   37.49 +if __name__ == "__main__":
   37.50 +    main()
   37.51 \ No newline at end of file
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test7.py	Thu Jul 22 13:42:39 2004 +0000
    38.3 @@ -0,0 +1,48 @@
    38.4 +#!/usr/bin/env python
    38.5 +#
    38.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    38.7 +#
    38.8 +# Permission to use, copy, modify, and distribute this software and its
    38.9 +# documentation for any purpose and without fee is hereby granted,
   38.10 +# provided that the above copyright notice appear in all copies and that
   38.11 +# both that copyright notice and this permission notice appear in
   38.12 +# supporting documentation, and that the name of Vinay Sajip
   38.13 +# not be used in advertising or publicity pertaining to distribution
   38.14 +# of the software without specific, written prior permission.
   38.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   38.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   38.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   38.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   38.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   38.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   38.21 +#
   38.22 +# This file is part of the Python logging distribution. See
   38.23 +# http://www.red-dove.com/python_logging.html
   38.24 +#
   38.25 +"""
   38.26 +A test harness for the logging module. Tests MemoryHandler.
   38.27 +
   38.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   38.29 +"""
   38.30 +import sys, logging, logging.handlers
   38.31 +
   38.32 +def message(s):
   38.33 +    sys.stderr.write("%s\n" % s)
   38.34 +
   38.35 +sh = logging.StreamHandler()
   38.36 +mh = logging.handlers.MemoryHandler(10,logging.WARNING, sh)
   38.37 +logger = logging.getLogger("")
   38.38 +logger.setLevel(logging.DEBUG)
   38.39 +logger.addHandler(mh)
   38.40 +message("-- logging at DEBUG, nothing should be seen yet --")
   38.41 +logger.debug("Debug message")
   38.42 +message("-- logging at INFO, nothing should be seen yet --")
   38.43 +logger.info("Info message")
   38.44 +message("-- logging at WARNING, 3 messages should be seen --")
   38.45 +logger.warning("Warning message")
   38.46 +for i in xrange(102):
   38.47 +    message("-- logging %d at level INFO, messages should be seen every 10 events --" % i)
   38.48 +    logger.info("Info index = %d", i)
   38.49 +sh.close()
   38.50 +mh.close()
   38.51 +logger.removeHandler(mh)
   38.52 \ No newline at end of file
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test8.py	Thu Jul 22 13:42:39 2004 +0000
    39.3 @@ -0,0 +1,69 @@
    39.4 +#!/usr/bin/env python
    39.5 +#
    39.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    39.7 +#
    39.8 +# Permission to use, copy, modify, and distribute this software and its
    39.9 +# documentation for any purpose and without fee is hereby granted,
   39.10 +# provided that the above copyright notice appear in all copies and that
   39.11 +# both that copyright notice and this permission notice appear in
   39.12 +# supporting documentation, and that the name of Vinay Sajip
   39.13 +# not be used in advertising or publicity pertaining to distribution
   39.14 +# of the software without specific, written prior permission.
   39.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   39.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   39.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   39.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   39.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   39.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   39.21 +#
   39.22 +# This file is part of the Python logging distribution. See
   39.23 +# http://www.red-dove.com/python_logging.html
   39.24 +#
   39.25 +"""
   39.26 +A test harness for the logging module. Tests FileHandler rollover.
   39.27 +
   39.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   39.29 +"""
   39.30 +import logging, logging.handlers
   39.31 +import locale
   39.32 +
   39.33 +locale.setlocale(locale.LC_ALL, '')
   39.34 +
   39.35 +sequence = 0
   39.36 +
   39.37 +def doLog(logger):
   39.38 +    global sequence
   39.39 +    sequence = sequence + 1
   39.40 +    logger.debug("%6d This message should be at level %d - %s", sequence,\
   39.41 +                logging.DEBUG, logging.getLevelName(logging.DEBUG))
   39.42 +    sequence = sequence + 1
   39.43 +    logger.info("%6d This message should be at level %d - %s", sequence,
   39.44 +                logging.INFO, logging.getLevelName(logging.INFO))
   39.45 +    sequence = sequence + 1
   39.46 +    logger.warning("%6d This message should be at level %d - %s", sequence,\
   39.47 +                logging.WARNING, logging.getLevelName(logging.WARNING))
   39.48 +    sequence = sequence + 1
   39.49 +    logger.error("%6d This message should be at level %d - %s", sequence,\
   39.50 +                logging.ERROR, logging.getLevelName(logging.ERROR))
   39.51 +    sequence = sequence + 1
   39.52 +    logger.critical("%6d This message should be at level %d - %s", sequence,\
   39.53 +                logging.CRITICAL, logging.getLevelName(logging.CRITICAL))
   39.54 +
   39.55 +def main():
   39.56 +    logger = logging.getLogger("")  #root logger
   39.57 +    logger.setLevel(logging.DEBUG)
   39.58 +    if __name__ == "__main__":
   39.59 +        logname = "rollover.log"
   39.60 +    else:
   39.61 +        logname = "log_test_rollover.log"
   39.62 +    hdlr = logging.handlers.RotatingFileHandler(logname, "a", 5000, 3)
   39.63 +    if __name__ == "__main__":
   39.64 +       fmt = logging.Formatter("%(asctime)s %(levelname)-5s %(message)s", "%x %X")
   39.65 +       hdlr.setFormatter(fmt)
   39.66 +    logger.addHandler(hdlr)
   39.67 +    for i in xrange(100):
   39.68 +        doLog(logger)
   39.69 +    logger.removeHandler(hdlr)
   39.70 +
   39.71 +if __name__ == "__main__":
   39.72 +    main()
   39.73 \ No newline at end of file
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/tools/python/logging/logging-0.4.9.2/test/log_test9.py	Thu Jul 22 13:42:39 2004 +0000
    40.3 @@ -0,0 +1,71 @@
    40.4 +#!/usr/bin/env python
    40.5 +#
    40.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    40.7 +#
    40.8 +# Permission to use, copy, modify, and distribute this software and its
    40.9 +# documentation for any purpose and without fee is hereby granted,
   40.10 +# provided that the above copyright notice appear in all copies and that
   40.11 +# both that copyright notice and this permission notice appear in
   40.12 +# supporting documentation, and that the name of Vinay Sajip
   40.13 +# not be used in advertising or publicity pertaining to distribution
   40.14 +# of the software without specific, written prior permission.
   40.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   40.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   40.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   40.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   40.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   40.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   40.21 +#
   40.22 +# This file is part of the Python logging distribution. See
   40.23 +# http://www.red-dove.com/python_logging.html
   40.24 +#
   40.25 +"""
   40.26 +A test harness for the logging module. Tests BufferingHandler, BufferingFormatter.
   40.27 +
   40.28 +Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
   40.29 +"""
   40.30 +import logging, logging.handlers
   40.31 +
   40.32 +class XMLFormatter(logging.BufferingFormatter):
   40.33 +        """
   40.34 +        A formatter which formats a set of records using XML, using an example DTD called "logging.dtd".
   40.35 +        """
   40.36 +        def __init__(self):
   40.37 +            fmtstr = """
   40.38 +    <event name="%(name)s" level="%(levelno)d" filename="%(filename)s" lineno="%(lineno)d">
   40.39 +    <message>%(message)s</message>
   40.40 +    </event>"""
   40.41 +            logging.BufferingFormatter.__init__(self, logging.Formatter(fmtstr))
   40.42 +
   40.43 +#   def formatHeader(self, records):
   40.44 +#       return """
   40.45 +#<?xml version="1.0" ?><!DOCTYPE eventSet SYSTEM "logging.dtd">
   40.46 +#<eventSet xmlns="http://www.red-dove.com/logging">"""
   40.47 +#
   40.48 +#   def formatFooter(self, records):
   40.49 +#       return "</eventSet>"
   40.50 +
   40.51 +class XMLHandler(logging.handlers.BufferingHandler):
   40.52 +    def __init__(self, capacity):
   40.53 +        logging.handlers.BufferingHandler.__init__(self, capacity)
   40.54 +        self.setFormatter(XMLFormatter())
   40.55 +
   40.56 +    def flush(self):
   40.57 +        if len(self.buffer) > 0:
   40.58 +            file = open("events.xml","w")
   40.59 +            file.write(self.formatter.format(self.buffer))
   40.60 +            file.close()
   40.61 +            self.buffer = []
   40.62 +
   40.63 +def main():
   40.64 +    logger = logging.getLogger("")
   40.65 +    logger.setLevel(logging.DEBUG)
   40.66 +    xh = XMLHandler(10)
   40.67 +    logger.addHandler(xh)
   40.68 +    for i in xrange(100):
   40.69 +        logger.info("Info index = %d", i)
   40.70 +    xh.close()
   40.71 +    logger.removeHandler(xh)
   40.72 +
   40.73 +if __name__ == "__main__":
   40.74 +    main()
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/tools/python/logging/logging-0.4.9.2/test/logconf.ini	Thu Jul 22 13:42:39 2004 +0000
    41.3 @@ -0,0 +1,180 @@
    41.4 +[loggers]
    41.5 +keys=root,log02,log03,log04,log05,log06,log07
    41.6 +
    41.7 +[handlers]
    41.8 +keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09
    41.9 +
   41.10 +[formatters]
   41.11 +keys=form01,form02,form03,form04,form05,form06,form07,form08,form09
   41.12 +
   41.13 +[logger_root]
   41.14 +level=NOTSET
   41.15 +propagate=1
   41.16 +channel=
   41.17 +parent=
   41.18 +qualname=(root)
   41.19 +handlers=hand01
   41.20 +
   41.21 +[logger_log02]
   41.22 +level=DEBUG
   41.23 +propagate=1
   41.24 +channel=log02
   41.25 +parent=(root)
   41.26 +qualname=log02
   41.27 +handlers=hand02
   41.28 +
   41.29 +[logger_log03]
   41.30 +level=INFO
   41.31 +propagate=1
   41.32 +channel=log03
   41.33 +parent=log02
   41.34 +qualname=log02.log03
   41.35 +handlers=hand03
   41.36 +
   41.37 +[logger_log04]
   41.38 +level=WARN
   41.39 +propagate=0
   41.40 +channel=log04
   41.41 +parent=log03
   41.42 +qualname=log02.log03.log04
   41.43 +handlers=hand04
   41.44 +
   41.45 +[logger_log05]
   41.46 +level=ERROR
   41.47 +propagate=1
   41.48 +channel=log05
   41.49 +parent=log04
   41.50 +qualname=log02.log03.log04.log05
   41.51 +handlers=hand05
   41.52 +
   41.53 +[logger_log06]
   41.54 +level=CRITICAL
   41.55 +propagate=1
   41.56 +channel=log06
   41.57 +parent=log05
   41.58 +qualname=log02.log03.log04.log05.log06
   41.59 +handlers=hand06
   41.60 +
   41.61 +[logger_log07]
   41.62 +level=WARN
   41.63 +propagate=1
   41.64 +channel=log07
   41.65 +parent=log06
   41.66 +qualname=log02.log03.log04.log05.log06.log07
   41.67 +handlers=hand07
   41.68 +
   41.69 +[handler_hand01]
   41.70 +class=StreamHandler
   41.71 +level=NOTSET
   41.72 +formatter=form01
   41.73 +stream=sys.stdout
   41.74 +args=(sys.stdout,)
   41.75 +
   41.76 +[handler_hand02]
   41.77 +class=FileHandler
   41.78 +level=DEBUG
   41.79 +formatter=form02
   41.80 +filename=python.log
   41.81 +mode=w
   41.82 +args=('python.log', 'w')
   41.83 +
   41.84 +[handler_hand03]
   41.85 +class=handlers.SocketHandler
   41.86 +level=INFO
   41.87 +formatter=form03
   41.88 +host=localhost
   41.89 +port=handlers.DEFAULT_TCP_LOGGING_PORT
   41.90 +args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)
   41.91 +
   41.92 +[handler_hand04]
   41.93 +class=handlers.DatagramHandler
   41.94 +level=WARN
   41.95 +formatter=form04
   41.96 +host=localhost
   41.97 +port=handlers.DEFAULT_UDP_LOGGING_PORT
   41.98 +args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)
   41.99 +
  41.100 +[handler_hand05]
  41.101 +class=handlers.SysLogHandler
  41.102 +level=ERROR
  41.103 +formatter=form05
  41.104 +host=localhost
  41.105 +port=handlers.SYSLOG_UDP_PORT
  41.106 +facility=LOG_USER
  41.107 +args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
  41.108 +
  41.109 +[handler_hand06]
  41.110 +class=handlers.NTEventLogHandler
  41.111 +level=CRITICAL
  41.112 +formatter=form06
  41.113 +appname=Python Application
  41.114 +dllname=
  41.115 +logtype=Application
  41.116 +args=('Python Application', '', 'Application')
  41.117 +
  41.118 +[handler_hand07]
  41.119 +class=handlers.SMTPHandler
  41.120 +level=WARN
  41.121 +formatter=form07
  41.122 +host=localhost
  41.123 +port=25
  41.124 +from=from@abc
  41.125 +to=user1@abc,user2@xyz
  41.126 +subject=Logger Subject
  41.127 +args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
  41.128 +
  41.129 +[handler_hand08]
  41.130 +class=handlers.MemoryHandler
  41.131 +level=NOTSET
  41.132 +formatter=form08
  41.133 +capacity=10
  41.134 +flushlevel=ERROR
  41.135 +target=
  41.136 +args=(10, ERROR)
  41.137 +
  41.138 +[handler_hand09]
  41.139 +class=handlers.HTTPHandler
  41.140 +level=NOTSET
  41.141 +formatter=form09
  41.142 +host=localhost
  41.143 +port=9022
  41.144 +url=/log
  41.145 +method=GET
  41.146 +args=('localhost:9022', '/log', 'GET')
  41.147 +
  41.148 +[formatter_form01]
  41.149 +format=F1 %(asctime)s %(levelname)s %(message)s
  41.150 +datefmt=
  41.151 +
  41.152 +[formatter_form02]
  41.153 +format=F2 %(asctime)s %(pathname)s(%(lineno)d): %(levelname)s %(message)s
  41.154 +datefmt=
  41.155 +
  41.156 +[formatter_form03]
  41.157 +format=F3 %(asctime)s %(levelname)s %(message)s
  41.158 +datefmt=
  41.159 +
  41.160 +[formatter_form04]
  41.161 +format=%(asctime)s %(levelname)s %(message)s
  41.162 +datefmt=
  41.163 +
  41.164 +[formatter_form05]
  41.165 +format=F5 %(asctime)s %(levelname)s %(message)s
  41.166 +datefmt=
  41.167 +
  41.168 +[formatter_form06]
  41.169 +format=F6 %(asctime)s %(levelname)s %(message)s
  41.170 +datefmt=
  41.171 +
  41.172 +[formatter_form07]
  41.173 +format=F7 %(asctime)s %(levelname)s %(message)s
  41.174 +datefmt=
  41.175 +
  41.176 +[formatter_form08]
  41.177 +format=F8 %(asctime)s %(levelname)s %(message)s
  41.178 +datefmt=
  41.179 +
  41.180 +[formatter_form09]
  41.181 +format=F9 %(asctime)s %(levelname)s %(message)s
  41.182 +datefmt=
  41.183 +
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/tools/python/logging/logging-0.4.9.2/test/logconf.py	Thu Jul 22 13:42:39 2004 +0000
    42.3 @@ -0,0 +1,1738 @@
    42.4 +#!/usr/bin/env python
    42.5 +#
    42.6 +# Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
    42.7 +#
    42.8 +# Permission to use, copy, modify, and distribute this software and its
    42.9 +# documentation for any purpose and without fee is hereby granted,
   42.10 +# provided that the above copyright notice appear in all copies and that
   42.11 +# both that copyright notice and this permission notice appear in
   42.12 +# supporting documentation, and that the name of Vinay Sajip
   42.13 +# not be used in advertising or publicity pertaining to distribution
   42.14 +# of the software without specific, written prior permission.
   42.15 +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   42.16 +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   42.17 +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   42.18 +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
   42.19 +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   42.20 +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   42.21 +#
   42.22 +# This file is part of the Python logging distribution. See
   42.23 +# http://www.red-dove.com/python_logging.html
   42.24 +#
   42.25 +
   42.26 +"""
   42.27 +A simple-minded GUI configurator for the logging module, using Tkinter.
   42.28 +
   42.29 +Should work under Python versions >= 1.5.2.
   42.30 +
   42.31 +Copyright (C) 2002 Vinay Sajip. All Rights Reserved.
   42.32 +
   42.33 +Configuration files are read/written using ConfigParser.
   42.34 +"""
   42.35 +"""
   42.36 +
   42.37 +(C) 2002 Vinay Sajip. All rights reserved.
   42.38 +"""
   42.39 +from Tkinter import *
   42.40 +from tkFileDialog import *
   42.41 +from tkMessageBox import *
   42.42 +
   42.43 +import os, sys, string, types
   42.44 +import ConfigParser
   42.45 +
   42.46 +active = None
   42.47 +
   42.48 +__version__ = "0.4.1"
   42.49 +
   42.50 +DEFAULT_FILENAME = "logconf.ini"
   42.51 +
   42.52 +LOGGING_LEVELS = (
   42.53 +    ("NOTSET", "NOTSET"),
   42.54 +    ("DEBUG", "DEBUG"),
   42.55 +    ("INFO", "INFO"),
   42.56 +    ("WARNING", "WARNING"),
   42.57 +    ("ERROR", "ERROR"),
   42.58 +    ("CRITICAL", "CRITICAL")
   42.59 +)
   42.60 +
   42.61 +HANDLER_TYPES = (
   42.62 +    ("StreamHandlerProxy", "StreamHandler"),
   42.63 +    ("FileHandlerProxy", "FileHandler"),
   42.64 +    ("RotatingFileHandlerProxy", "RotatingFileHandler"),
   42.65 +    ("SocketHandlerProxy", "SocketHandler"),
   42.66 +    ("DatagramHandlerProxy", "DatagramHandler"),
   42.67 +    ("SysLogHandlerProxy", "SysLogHandler"),
   42.68 +    ("NTEventLogHandlerProxy", "NTEventLogHandler"),
   42.69 +    ("SMTPHandlerProxy", "SMTPHandler"),
   42.70 +    ("MemoryHandlerProxy", "MemoryHandler"),
   42.71 +    ("HTTPHandlerProxy", "HTTPHandler"),
   42.72 +#    ("SOAPHandlerProxy", "SOAPHandler"),
   42.73 +)
   42.74 +
   42.75 +OUTPUT_STREAMS = (
   42.76 +    ("sys.stdout", "sys.stdout"),
   42.77 +    ("sys.stderr", "sys.stderr")
   42.78 +)
   42.79 +
   42.80 +FILE_MODES = (
   42.81 +    ("a", "a"),
   42.82 +    ("w", "w")
   42.83 + )
   42.84 +
   42.85 +HTTP_METHODS = (
   42.86 +    ("GET", "GET"),
   42.87 +    ("POST", "POST")
   42.88 +)
   42.89 +
   42.90 +SYSLOG_FACILITIES = (
   42.91 +    ("LOG_AUTH", "auth"),
   42.92 +    ("LOG_AUTHPRIV", "authpriv"),
   42.93 +    ("LOG_CRON", "cron"),
   42.94 +    ("LOG_DAEMON", "daemon"),
   42.95 +    ("LOG_KERN", "kern"),
   42.96 +    ("LOG_LPR", "lpr"),
   42.97 +    ("LOG_MAIL", "mail"),
   42.98 +    ("LOG_NEWS", "news"),
   42.99 +    ("LOG_AUTH", "security"),
  42.100 +    ("LOG_SYSLOG", "syslog"),
  42.101 +    ("LOG_USER", "user"),
  42.102 +    ("LOG_UUCP", "uucp"),
  42.103 +    ("LOG_LOCAL0", "local0"),
  42.104 +    ("LOG_LOCAL1", "local1"),
  42.105 +    ("LOG_LOCAL2", "local2"),
  42.106 +    ("LOG_LOCAL3", "local3"),
  42.107 +    ("LOG_LOCAL4", "local4"),
  42.108 +    ("LOG_LOCAL5", "local5"),
  42.109 +    ("LOG_LOCAL6", "local6"),
  42.110 +    ("LOG_LOCAL7", "local7"),
  42.111 +)
  42.112 +
  42.113 +LOG_TYPES = (
  42.114 +    ("Application", "Application"),
  42.115 +    ("System", "System"),
  42.116 +    ("Security", "Security")
  42.117 +)
  42.118 +
  42.119 +BOOLEAN_VALUES = (
  42.120 +    ("0", "False"),
  42.121 +    ("1", "True")
  42.122 +)
  42.123 +
  42.124 +class Property:
  42.125 +    def __init__(self, name, caption, value=None, choices=None):
  42.126 +        self.name = name
  42.127 +        self.caption = caption
  42.128 +        self.value = value
  42.129 +        self.choices = choices
  42.130 +
  42.131 +    def getChoices(self):
  42.132 +        return self.choices
  42.133 +
  42.134 +    def isvalid(self, s):
  42.135 +        return 0
  42.136 +
  42.137 +    def getCaption(self):
  42.138 +        return self.caption
  42.139 +
  42.140 +    def getValue(self):
  42.141 +        return self.value
  42.142 +
  42.143 +    def getChoiceText(self, val):
  42.144 +        rv = ""
  42.145 +        choices = self.getChoices()
  42.146 +        if choices:
  42.147 +            for choice in choices:
  42.148 +                if choice[0] == val:
  42.149 +                    rv = choice[1]
  42.150 +                    break
  42.151 +        return rv
  42.152 +
  42.153 +    def setValue(self, val):
  42.154 +        self.value = val
  42.155 +
  42.156 +    def getValueText(self):
  42.157 +        if type(self.value) in [types.ListType, types.TupleType]:
  42.158 +            v = list(self.value)
  42.159 +        else:
  42.160 +            v = [self.value]
  42.161 +        choices = self.getChoices()
  42.162 +        if choices:
  42.163 +            v = map(self.getChoiceText, v)
  42.164 +        return string.join(v, ',')
  42.165 +
  42.166 +class PropertyHolder:
  42.167 +    def __init__(self, dict):
  42.168 +        self.dict = dict
  42.169 +        self.propnames = []
  42.170 +        self.onPropListChanged = None
  42.171 +
  42.172 +    def getPropNames(self):
  42.173 +        """
  42.174 +        Return the property names in the order in which they are to
  42.175 +        be listed.
  42.176 +        """
  42.177 +        return self.propnames
  42.178 +
  42.179 +    def getProp(self, name):
  42.180 +        return self.dict[name]
  42.181 +
  42.182 +    def isReadonly(self, name):
  42.183 +        return 0
  42.184 +
  42.185 +    #convenience methods
  42.186 +    def getPropValue(self, name):
  42.187 +        return self.dict[name].value
  42.188 +
  42.189 +    def setPropValue(self, name, value):
  42.190 +        self.dict[name].setValue(value)
  42.191 +
  42.192 +LINE_COLOUR = '#999999'
  42.193 +
  42.194 +class ScrollingList(Frame):
  42.195 +    def __init__(self, parent, *args, **kwargs):
  42.196 +        Frame.__init__(self, parent)
  42.197 +        self.parent = parent
  42.198 +        self.listener = self.parent
  42.199 +        self.sb = Scrollbar(self, orient=VERTICAL)
  42.200 +        kwargs["yscrollcommand"] = self.sb.set
  42.201 +        self.list = apply(Listbox, (self,) + args, kwargs)
  42.202 +        self.sb.config(command=self.list.yview)
  42.203 +        self.sb.pack(side=RIGHT, fill=Y)
  42.204 +        self.list.pack(side=LEFT, fill=BOTH,expand=1)
  42.205 +        self.list.bind('<ButtonRelease-1>', self.onListChange)
  42.206 +        self.choices = None
  42.207 +
  42.208 +    def setContents(self, choices, value):
  42.209 +        self.choices = choices
  42.210 +        self.value = value
  42.211 +        self.list.delete(0, END)
  42.212 +        if type(value) == types.ListType:
  42.213 +            sm = EXTENDED
  42.214 +        else:
  42.215 +            sm = BROWSE
  42.216 +        self.list.configure(selectmode=sm)
  42.217 +        i = 0
  42.218 +        for choice in choices:
  42.219 +            self.list.insert(END, choice[1])
  42.220 +            if sm == EXTENDED:
  42.221 +                if choice[0] in value:
  42.222 +                    self.list.select_set(i)
  42.223 +            else:
  42.224 +                if choice[0] == value:
  42.225 +                    self.list.select_set(i)
  42.226 +            i = i + 1
  42.227 +
  42.228 +    def getValue(self):
  42.229 +        if type(self.value) == types.ListType:
  42.230 +            multi = 1
  42.231 +            rv = []
  42.232 +        else:
  42.233 +            multi = 0
  42.234 +        for i in xrange(len(self.choices)):
  42.235 +            if self.list.select_includes(i):
  42.236 +                if not multi:
  42.237 +                    rv = self.choices[i][0]
  42.238 +                    break
  42.239 +                else:
  42.240 +                    rv.append(self.choices[i][0])
  42.241 +        return rv
  42.242 +
  42.243 +    def onListChange(self, event):
  42.244 +        self.value = self.getValue()
  42.245 +        self.listener.onListChange(self.value)
  42.246 +
  42.247 +class PropertyHeader(Canvas):
  42.248 +    def __init__(self, parent, *args, **kwargs):
  42.249 +        self.namewidth = 120
  42.250 +        if kwargs.has_key("namewidth"):
  42.251 +            self.namewidth = kwargs["namewidth"]
  42.252 +            del kwargs["namewidth"]
  42.253 +        self.rowheight = 16
  42.254 +        if kwargs.has_key("rowheight"):
  42.255 +            self.rowheight = kwargs["rowheight"]
  42.256 +            del kwargs["rowheight"]
  42.257 +        apply(Canvas.__init__, (self, parent)+args, kwargs)
  42.258 +        self.bind('<Configure>', self.onConfigure)
  42.259 +        x = 5
  42.260 +        y = 0
  42.261 +        wid = int(self.cget('width'))
  42.262 +        self.create_text(x, y, text='Property', anchor='nw')
  42.263 +        self.create_text(x + self.namewidth, y, text='Value', anchor='nw')
  42.264 +        self.create_line(self.namewidth, 0, self.namewidth, self.rowheight, fill=LINE_COLOUR)
  42.265 +        self.tline = self.create_line(0, 0, wid, 0, fill=LINE_COLOUR)
  42.266 +        #self.create_line(0, 0, 0, self.rowheight, fill=LINE_COLOUR)
  42.267 +        #self.create_line(wid - 1, 0, wid - 1, self.rowheight, fill=LINE_COLOUR)
  42.268 +
  42.269 +    def onConfigure(self, event):
  42.270 +        self.delete(self.tline)
  42.271 +        self.tline = self.create_line(0, 0, event.width, 0, fill=LINE_COLOUR)
  42.272 +
  42.273 +_popup = None
  42.274 +
  42.275 +class PropertyCanvas(Canvas):
  42.276 +    def __init__(self, parent, *args, **kwargs):
  42.277 +        self.namewidth = 120
  42.278 +        if kwargs.has_key("namewidth"):
  42.279 +            self.namewidth = kwargs["namewidth"]
  42.280 +            del kwargs["namewidth"]
  42.281 +        self.rowheight = 16
  42.282 +        if kwargs.has_key("rowheight"):
  42.283 +            self.rowheight = kwargs["rowheight"]
  42.284 +            del kwargs["rowheight"]
  42.285 +        apply(Canvas.__init__, (self, parent)+args, kwargs)
  42.286 +        self.namitems = []
  42.287 +        self.valitems = []
  42.288 +        self.lines = []
  42.289 +        self.pnames = []
  42.290 +        #Event bindings...
  42.291 +        self.bind('<Enter>', self.onEnter)
  42.292 +        self.bind('<Button-1>', self.onClick)
  42.293 +        self.bind('<Configure>', self.onConfigure)
  42.294 +        self.button = Button(height=self.rowheight, width=self.rowheight, text='...', command=self.onEdit)
  42.295 +        self.btnitem = None
  42.296 +        self.editor = Entry()
  42.297 +        self.edititem = None
  42.298 +        self.popup = Toplevel()
  42.299 +        self.popup.withdraw()
  42.300 +        self.popup.overrideredirect(1)
  42.301 +        self.list = ScrollingList(self.popup, background='white', relief=FLAT, borderwidth=0)
  42.302 +        self.list.pack(fill=BOTH, expand=1)
  42.303 +        self.list.listener = self
  42.304 +        self.listvisible = 0
  42.305 +
  42.306 +    def clear(self):
  42.307 +        for itm in self.namitems:
  42.308 +            self.delete(itm)
  42.309 +        self.namitems = []
  42.310 +        for itm in self.valitems:
  42.311 +            self.delete(itm)
  42.312 +        self.valitems = []
  42.313 +        for lin in self.lines:
  42.314 +            self.delete(lin)
  42.315 +        self.lines = []
  42.316 +
  42.317 +    def setPropertyHolder(self, ph):
  42.318 +        self.ph = ph
  42.319 +        self.pnames = ph.getPropNames()
  42.320 +        wid = int(self.cget('width'))
  42.321 +        hei = int(self.cget('height'))
  42.322 +        self.clear()
  42.323 +        x = 5
  42.324 +        y = 0
  42.325 +        i = 0
  42.326 +        self.props = []
  42.327 +        for n in self.pnames:
  42.328 +            prop = self.ph.getProp(n)
  42.329 +            self.props.append(prop)
  42.330 +            tn = "n%d" % i
  42.331 +            tv = "v%d" % i
  42.332 +            self.namitems.append(self.create_text(x, y + 2, text=prop.getCaption(), anchor='nw', tags=tn))
  42.333 +            self.valitems.append(self.create_text(x + self.namewidth, y + 2, text=prop.getValueText(), anchor='nw', tags=tv))
  42.334 +            y = y + self.rowheight
  42.335 +            i = i + 1
  42.336 +        self.drawLines(wid, hei)
  42.337 +        #self.config(height=y)
  42.338 +
  42.339 +    def drawLines(self, wid, hei):
  42.340 +        for lin in self.lines:
  42.341 +            self.delete(lin)
  42.342 +        self.lines = []
  42.343 +        y = 0
  42.344 +        for i in xrange(len(self.pnames)):
  42.345 +            self.lines.append(self.create_line(0, y, wid, y, fill=LINE_COLOUR))
  42.346 +            y = y + self.rowheight
  42.347 +        self.lines.append(self.create_line(0, y, wid, y, fill=LINE_COLOUR))
  42.348 +        self.create_line(self.namewidth, 0, self.namewidth, hei, fill=LINE_COLOUR)
  42.349 +
  42.350 +    def onEnter(self, event):
  42.351 +        if not self.edititem and not self.listvisible:
  42.352 +            self.focus_set()
  42.353 +
  42.354 +    def hideControls(self):
  42.355 +        if self.listvisible:
  42.356 +            self.popup.withdraw()
  42.357 +            global _popup
  42.358 +            _popup = None
  42.359 +            self.listvisible = 0
  42.360 +        if self.edititem:
  42.361 +            self.ph.setPropValue(self.editprop.name, self.editor.get())
  42.362 +            self.itemconfig(self.valitems[self.editrow], text=self.editprop.getValueText())
  42.363 +            self.delete(self.edititem)
  42.364 +            self.edititem = None
  42.365 +        if self.btnitem:
  42.366 +            self.delete(self.btnitem)
  42.367 +            self.btnitem = None
  42.368 +
  42.369 +    def onClick(self, event):
  42.370 +        row = event.y / self.rowheight
  42.371 +        self.hideControls()
  42.372 +        if row < len(self.pnames):
  42.373 +            wid = int(self.cget('width'))
  42.374 +            hei = self.rowheight
  42.375 +            prop = self.props[row]
  42.376 +            if not self.ph.isReadonly(self.pnames[row]):
  42.377 +                self.editrow = row
  42.378 +                self.editprop = prop
  42.379 +                choices = prop.getChoices()
  42.380 +                if choices != None:
  42.381 +                    val = prop.getValue()
  42.382 +                    self.list.setContents(choices, val)
  42.383 +                    self.listy = row * hei + self.rowheight
  42.384 +                    self.btnitem = self.create_window(wid - hei, row * hei, width=hei, height=hei, window=self.button, anchor='nw', tags='button')
  42.385 +                else:
  42.386 +                    self.editor.delete(0, END)
  42.387 +                    self.editor.insert(0, prop.getValueText())
  42.388 +                    self.editor.select_range(0, END)
  42.389 +                    self.edititem = self.create_window(self.namewidth + 1, row * hei, width=wid - self.namewidth, height = hei + 1, window=self.editor, anchor='nw', tags='editor')
  42.390 +                    self.editor.focus_set()
  42.391 +
  42.392 +    def onConfigure(self, event):
  42.393 +        self.hideControls()
  42.394 +        self.drawLines(event.width, event.height)
  42.395 +        self.configure(width=event.width, height=event.height)
  42.396 +
  42.397 +    def onEdit(self):
  42.398 +        wid = int(self.cget('width'))
  42.399 +        #self.listitem = self.create_window(self.namewidth + 1, self.listy, width=wid - self.namewidth - 1, height = self.rowheight * 3, window=self.list, anchor='nw', tags='list')
  42.400 +        w = wid - self.namewidth - 1
  42.401 +        h = self.rowheight * 5
  42.402 +        x = self.winfo_rootx() + self.namewidth + 1
  42.403 +        y = self.winfo_rooty() + self.listy
  42.404 +        s = "%dx%d+%d+%d" % (w, h, x, y)
  42.405 +        self.popup.deiconify()
  42.406 +        self.popup.lift()
  42.407 +        self.popup.focus_set()
  42.408 +        self.listvisible = 1
  42.409 +        self.list.focus_set()
  42.410 +        #For some reason with 1.5.2 (Windows), making the geometry call
  42.411 +        #immediately following the assignment to s doesn't work. So we
  42.412 +        #do it here
  42.413 +        self.popup.geometry(s)
  42.414 +        global _popup
  42.415 +        _popup = self.popup
  42.416 +
  42.417 +    def onListChange(self, val):
  42.418 +        self.ph.setPropValue(self.editprop.name, val)
  42.419 +        self.itemconfig(self.valitems[self.editrow], text=self.editprop.getValueText())
  42.420 +        if type(val) != types.ListType:
  42.421 +            self.hideControls()
  42.422 +
  42.423 +class PropertyEditor(Frame):
  42.424 +    def __init__(self, parent, *args, **kwargs):
  42.425 +        Frame.__init__(self, parent)
  42.426 +        self.parent = parent
  42.427 +        nw = kwargs.get("namewidth", 120)
  42.428 +        rh = kwargs.get("rowheight", 16)
  42.429 +        wid = kwargs.get("width", 300)
  42.430 +        hei = kwargs.get("height", 60)
  42.431 +        self.header = PropertyHeader(self, namewidth=nw, rowheight=rh, height=14, highlightthickness=0)
  42.432 +        self.body = PropertyCanvas(self, namewidth=nw, rowheight=rh, width=wid, height=hei, background='white', highlightthickness=0)
  42.433 +        self.header.pack(side=TOP, fill=X)
  42.434 +        self.body.pack(side=BOTTOM, fill=BOTH, expand=1)
  42.435 +
  42.436 +    def setPropertyHolder(self, ph):
  42.437 +        self.body.setPropertyHolder(ph)
  42.438 +
  42.439 +class ADUPanel(Frame):
  42.440 +    def __init__(self, parent):
  42.441 +        Frame.__init__(self, parent)
  42.442 +        self.parent = parent
  42.443 +        self.add = Button(self, text="New", command=parent.onAdd)
  42.444 +        self.add.pack(side=LEFT) #, fill=X, expand=1)
  42.445 +        self.rmv = Button(self, text="Delete", command=parent.onDelete)
  42.446 +        self.rmv.pack(side=LEFT) #, fill=X, expand=1)
  42.447 +        #self.upd = Button(self, text="Update", command=parent.onUpdate)
  42.448 +        #self.upd.pack(side=RIGHT, fill=X, expand=1)
  42.449 +
  42.450 +class ScrollList(Frame):
  42.451 +    def __init__(self, parent, *args, **kwargs):
  42.452 +        Frame.__init__(self, parent)
  42.453 +        self.parent = parent
  42.454 +        self.sb = Scrollbar(self, orient=VERTICAL)
  42.455 +        kwargs["yscrollcommand"] = self.sb.set
  42.456 +        self.list = apply(Listbox, (self,) + args, kwargs)
  42.457 +        self.sb.config(command=self.list.yview)
  42.458 +        self.sb.pack(side=RIGHT, fill=Y)
  42.459 +        self.list.pack(side=LEFT, fill=BOTH,expand=1)
  42.460 +
  42.461 +def sortqn(log1, log2):
  42.462 +    qn1 = log1.getQualifiedName()
  42.463 +    qn2 = log2.getQualifiedName()
  42.464 +    if qn1 == "(root)":
  42.465 +        rv = -1
  42.466 +    elif qn2 == "(root)":
  42.467 +        rv = 1
  42.468 +    else:
  42.469 +        rv = cmp(qn1, qn2)
  42.470 +    return rv
  42.471 +
  42.472 +def sortn(obj1, obj2):
  42.473 +    return cmp(obj1.getPropValue("name"), obj2.getPropValue("name"))
  42.474 +
  42.475 +class LoggerPanel(Frame):
  42.476 +    def __init__(self, parent):
  42.477 +        Frame.__init__(self, parent)
  42.478 +        self.parent = parent
  42.479 +        label = Label(self, text="Loggers:")
  42.480 +        label.grid(row=0, column=0, sticky='w')
  42.481 +        self.slist = ScrollList(self, height=15, background='white')
  42.482 +        self.slist.list.bind('<ButtonRelease-1>', self.onListChange)
  42.483 +        self.slist.grid(row=1, column=0, sticky="nsew")
  42.484 +        self.adu = ADUPanel(self)
  42.485 +        self.adu.grid(row=2, column=0, sticky="we")
  42.486 +        label = Label(self, text="Properties of selected logger:")
  42.487 +        label.grid(row=3, column=0, sticky='w')
  42.488 +        self.pe = PropertyEditor(self, height=120, borderwidth=1)
  42.489 +        self.pe.grid(row=4, column=0, sticky='nsew')
  42.490 +        self.columnconfigure(0, weight=1)
  42.491 +        self.rowconfigure(1, weight=3)
  42.492 +        self.rowconfigure(4, weight=1)
  42.493 +
  42.494 +    def setConfig(self, config):
  42.495 +        self.config = config
  42.496 +        #populate list of loggers
  42.497 +        llist = config.getLoggers()
  42.498 +        llist.sort(sortqn)
  42.499 +        self.slist.list.delete(0, END)
  42.500 +        self.pe.body.clear()
  42.501 +        self.names = []
  42.502 +        for logger in llist:
  42.503 +            self.names.append(logger.getPropValue("name"))
  42.504 +            self.slist.list.insert(END, logger.getQualifiedName())
  42.505 +
  42.506 +    def onAdd(self):
  42.507 +        items = self.slist.list.curselection()
  42.508 +        if not len(items):
  42.509 +            showerror("No Parent Selected", "You haven't selected a parent logger.")
  42.510 +        else:
  42.511 +            idx = int(items[0])
  42.512 +            parent = self.config.getLogger(self.names[idx])
  42.513 +            log = self.config.getLogger(None)
  42.514 +            log.onChannelChanged = self.onChannelChanged
  42.515 +            log.setPropValue("parent", parent.getPropValue("name"))
  42.516 +            self.names.insert(1 + idx, log.getPropValue("name"))
  42.517 +            self.slist.list.insert(1 + idx, log.getQualifiedName())
  42.518 +            self.slist.list.select_clear(0, END)
  42.519 +            self.slist.list.select_set(1 + idx)
  42.520 +            self.pe.setPropertyHolder(log)
  42.521 +
  42.522 +    def onDelete(self):
  42.523 +        items = self.slist.list.curselection()
  42.524 +        if not len(items):
  42.525 +            showerror("No Item Selected", "You haven't selected anything to delete.")
  42.526 +        else:
  42.527 +            idx = int(items[0])
  42.528 +            name = self.slist.list.get(idx)
  42.529 +            if name == "(root)":
  42.530 +                showerror("Root Item Selected", "You cannot delete the root logger.")
  42.531 +            else:
  42.532 +                resp = askyesno("Logger Deletion", "Are you sure you want to delete logger '%s'?" % name)
  42.533 +                if resp:
  42.534 +                    #self.config.removeLogger(self.names[idx])
  42.535 +                    log = self.config.getLogger(self.names[idx])
  42.536 +                    log.deleted = 1
  42.537 +                    self.slist.list.delete(idx)
  42.538 +                    del self.names[idx]
  42.539 +                    self.pe.body.clear()
  42.540 +
  42.541 +    def onChannelChanged(self, nm, chname):
  42.542 +        i = self.names.index(nm)
  42.543 +        sel = i
  42.544 +        while i < len(self.names):
  42.545 +            log = self.config.getLogger(self.names[i])
  42.546 +            self.slist.list.delete(i)
  42.547 +            self.slist.list.insert(i, log.getQualifiedName())
  42.548 +            i = i + 1
  42.549 +        self.slist.list.select_clear(0, END)
  42.550 +        self.slist.list.select_set(sel)
  42.551 +
  42.552 +    def onListChange(self, event):
  42.553 +        self.pe.body.hideControls()
  42.554 +        items = self.slist.list.curselection()
  42.555 +        idx = int(items[0])
  42.556 +        name = self.names[idx]
  42.557 +        log = self.config.getLogger(name)
  42.558 +        self.pe.setPropertyHolder(log)
  42.559 +
  42.560 +class HandlerPanel(Frame):
  42.561 +    def __init__(self, parent):
  42.562 +        Frame.__init__(self, parent)
  42.563 +        self.parent = parent
  42.564 +        label = Label(self, text="Handlers:")
  42.565 +        label.grid(row=0, column=0, sticky='w')
  42.566 +        self.slist = ScrollList(self, height=6, background='white')
  42.567 +        self.slist.list.bind('<ButtonRelease-1>', self.onListChange)
  42.568 +        self.slist.grid(row=1, column=0, sticky="nsew")
  42.569 +        self.adu = ADUPanel(self)
  42.570 +        self.adu.grid(row=2, column=0, sticky="we")
  42.571 +        label = Label(self, text="Properties of selected handler:")
  42.572 +        label.grid(row=3, column=0, sticky='w')
  42.573 +        self.pe = PropertyEditor(self, height=90, borderwidth=1)
  42.574 +        self.pe.grid(row=4, column=0, sticky='nsew')
  42.575 +        self.columnconfigure(0, weight=1)
  42.576 +        self.rowconfigure(1, weight=1)
  42.577 +        self.rowconfigure(4, weight=1)
  42.578 +
  42.579 +    def setConfig(self, config):
  42.580 +        self.config = config
  42.581 +        #populate list of handlers
  42.582 +        hlist = config.getHandlers()
  42.583 +        hlist.sort(sortn)
  42.584 +        self.slist.list.delete(0, END)
  42.585 +        self.pe.body.clear()
  42.586 +        for hand in hlist:
  42.587 +            hand.onPropListChanged = self.onPropListChanged
  42.588 +            self.slist.list.insert(END, hand.getPropValue("name"))
  42.589 +
  42.590 +    def onAdd(self):
  42.591 +        self.pe.body.hideControls()
  42.592 +        hand = self.config.getHandler(None)
  42.593 +        self.slist.list.insert(END, hand.getProp("name").getValueText())
  42.594 +        self.slist.list.select_clear(0, END)
  42.595 +        self.slist.list.select_set(END)
  42.596 +        hand.onPropListChanged = self.onPropListChanged
  42.597 +        self.pe.setPropertyHolder(hand)
  42.598 +
  42.599 +    def onDelete(self):
  42.600 +        items = self.slist.list.curselection()
  42.601 +        if not len(items):
  42.602 +            showerror("No Item Selected", "You haven't selected anything to delete")
  42.603 +        else:
  42.604 +            name = self.slist.list.get(int(items[0]))
  42.605 +            log = self.config.handlerIsUsed(name)
  42.606 +            if log:
  42.607 +                showerror("Handler in use",
  42.608 +                          "The handler '%s' is being used by logger '%s'"\
  42.609 +                          ", so it cannot be deleted." % (
  42.610 +                          name, log))
  42.611 +            else:
  42.612 +                self.config.removeHandler(name)
  42.613 +                self.slist.list.delete(items)
  42.614 +                self.pe.body.clear()
  42.615 +
  42.616 +    def onUpdate(self):
  42.617 +        print "handler update"
  42.618 +
  42.619 +    def onListChange(self, event):
  42.620 +        self.pe.body.hideControls()
  42.621 +        items = self.slist.list.curselection()
  42.622 +        name = self.slist.list.get(int(items[0]))
  42.623 +        hand = self.config.getHandler(name)
  42.624 +        self.pe.setPropertyHolder(hand)
  42.625 +
  42.626 +    def onPropListChanged(self, newhand):
  42.627 +        newhand.onPropListChanged = self.onPropListChanged
  42.628 +        self.pe.setPropertyHolder(newhand)
  42.629 +
  42.630 +class FormatterPanel(Frame):
  42.631 +    def __init__(self, parent):
  42.632 +        Frame.__init__(self, parent)
  42.633 +        self.parent = parent
  42.634 +        label = Label(self, text="Formatters:")
  42.635 +        label.grid(row=0, column=0, sticky='w')
  42.636 +        self.slist = ScrollList(self, height=4, background='white')
  42.637 +        self.slist.list.bind('<ButtonRelease-1>', self.onListChange)
  42.638 +        self.slist.grid(row=1, column=0, sticky="nsew")
  42.639 +        self.adu = ADUPanel(self)
  42.640 +        self.adu.grid(row=2, column=0, sticky="ew")
  42.641 +        label = Label(self, text="Properties of selected formatter:")
  42.642 +        label.grid(row=3, column=0, sticky='w')
  42.643 +        self.pe = PropertyEditor(self, height=60, borderwidth=1)
  42.644 +        self.pe.grid(row=4, column=0, sticky='nsew')
  42.645 +        self.columnconfigure(0, weight=1)
  42.646 +        self.rowconfigure(1, weight=1)
  42.647 +        self.rowconfigure(4, weight=1)
  42.648 +
  42.649 +    def setConfig(self, config):
  42.650 +        self.config = config
  42.651 +        #populate list of formatters
  42.652 +        flist = config.getFormatters()
  42.653 +        flist.sort(sortn)
  42.654 +        self.slist.list.delete(0, END)
  42.655 +        self.pe.body.clear()
  42.656 +        for form in flist:
  42.657 +            self.slist.list.insert(END, form.getPropValue("name"))
  42.658 +
  42.659 +    def onAdd(self):
  42.660 +        self.pe.body.hideControls()
  42.661 +        fmt = self.config.getFormatter(None)
  42.662 +        self.slist.list.insert(END, fmt.getProp("name").getValueText())
  42.663 +        self.slist.list.select_clear(0, END)
  42.664 +        i = self.slist.list.size()
  42.665 +        self.slist.list.select_set(i - 1)
  42.666 +        self.pe.setPropertyHolder(fmt)
  42.667 +
  42.668 +    def onDelete(self):
  42.669 +        self.pe.body.hideControls()
  42.670 +        items = self.slist.list.curselection()
  42.671 +        if not len(items):
  42.672 +            showerror("No Item Selected", "You haven't selected anything to delete")
  42.673 +        else:
  42.674 +            name = self.slist.list.get(int(items[0]))
  42.675 +            h = self.config.formatterIsUsed(name)
  42.676 +            if h:
  42.677 +                showerror("Formatter in use",
  42.678 +                          "The formatter '%s' is being used by handler '%s'"\
  42.679 +                          ", so it cannot be deleted." % (
  42.680 +                          name, h))
  42.681 +            else:
  42.682 +                self.config.removeFormatter(name)
  42.683 +                self.slist.list.delete(items)
  42.684 +                self.pe.body.clear()
  42.685 +
  42.686 +    def onUpdate(self):
  42.687 +        self.pe.body.hideControls()
  42.688 +
  42.689 +    def onListChange(self, event):
  42.690 +        self.pe.body.hideControls()
  42.691 +        items = self.slist.list.curselection()
  42.692 +        name = self.slist.list.get(int(items[0]))
  42.693 +        fmt = self.config.getFormatter(name)
  42.694 +        self.pe.setPropertyHolder(fmt)
  42.695 +
  42.696 +class FilterPanel(Frame):
  42.697 +    def __init__(self, parent):
  42.698 +        Frame.__init__(self, parent)
  42.699 +        self.parent = parent
  42.700 +        label = Label(self, text="Filters:")
  42.701 +        label.grid(row=0, column=0, sticky='w')
  42.702 +        self.slist = ScrollList(self, height=4, background='white')
  42.703 +        self.slist.list.bind('<ButtonRelease-1>', self.onListChange)
  42.704 +        self.slist.grid(row=1, column=0, sticky="nsew")
  42.705 +        self.adu = ADUPanel(self)
  42.706 +        self.adu.grid(row=2, column=0, sticky="ew")
  42.707 +        label = Label(self, text="Properties of selected filter:")
  42.708 +        label.grid(row=3, column=0, sticky='w')
  42.709 +        self.pe = PropertyEditor(self, height=60, borderwidth=1)
  42.710 +        self.pe.grid(row=4, column=0, sticky='nsew')
  42.711 +        self.columnconfigure(0, weight=1)
  42.712 +        self.rowconfigure(1, weight=1)
  42.713 +        self.rowconfigure(4, weight=1)
  42.714 +
  42.715 +    def setConfig(self, config):
  42.716 +        self.config = config
  42.717 +        #populate list of filters
  42.718 +        flist = config.getFilters()
  42.719 +        flist.sort(sortn)
  42.720 +        self.slist.list.delete(0, END)
  42.721 +        self.pe.body.clear()
  42.722 +        for filt in flist:
  42.723 +            self.slist.list.insert(END, filt.getPropValue("name"))
  42.724 +
  42.725 +    def onAdd(self):
  42.726 +        self.pe.body.hideControls()
  42.727 +        filt = self.config.getFilter(None)
  42.728 +        self.slist.list.insert(END, filt.getProp("name").getValueText())
  42.729 +        self.slist.list.select_clear(0, END)
  42.730 +        i = self.slist.list.size()
  42.731 +        self.slist.list.select_set(i - 1)
  42.732 +        self.pe.setPropertyHolder(filt)
  42.733 +
  42.734 +    def onDelete(self):
  42.735 +        self.pe.body.hideControls()
  42.736 +        items = self.slist.list.curselection()
  42.737 +        if not len(items):
  42.738 +            showerror("No Item Selected", "You haven't selected anything to delete")
  42.739 +        else:
  42.740 +            name = self.slist.list.get(int(items[0]))
  42.741 +            h = self.config.filterIsUsed(name)
  42.742 +            if h:
  42.743 +                showerror("Filter in use",
  42.744 +                          "The filter '%s' is being used by '%s'"\
  42.745 +                          ", so it cannot be deleted." % (
  42.746 +                          name, h))
  42.747 +            else:
  42.748 +                self.config.removeFilter(name)
  42.749 +                self.slist.list.delete(items)
  42.750 +                self.pe.body.clear()
  42.751 +
  42.752 +    def onUpdate(self):
  42.753 +        self.pe.body.hideControls()
  42.754 +
  42.755 +    def onListChange(self, event):
  42.756 +        self.pe.body.hideControls()
  42.757 +        items = self.slist.list.curselection()
  42.758 +        name = self.slist.list.get(int(items[0]))
  42.759 +        filt = self.config.getFilter(name)
  42.760 +        self.pe.setPropertyHolder(filt)
  42.761 +
  42.762 +class ConfigPanel(Frame):
  42.763 +    def __init__(self, parent):
  42.764 +        Frame.__init__(self, parent)
  42.765 +        self.parent = parent
  42.766 +        self.load = Button(self, text="Load...", command=parent.onLoad)
  42.767 +        self.load.pack(side=LEFT)
  42.768 +        self.save = Button(self, text="Save", command=parent.onSave)
  42.769 +        self.save.pack(side=LEFT)
  42.770 +        self.save = Button(self, text="Save as...", command=parent.onSaveAs)
  42.771 +        self.save.pack(side=LEFT)
  42.772 +        self.reset = Button(self, text="Reset", command=parent.onReset)
  42.773 +        self.reset.pack(side=RIGHT)
  42.774 +
  42.775 +class Configurator(Frame):
  42.776 +    def __init__(self, parent):
  42.777 +        Frame.__init__(self, parent)
  42.778 +        self.parent = parent
  42.779 +        self.llist = LoggerPanel(self)
  42.780 +        self.llist.grid(row=0, column=0, rowspan=2, sticky='nsew')
  42.781 +        spacer = Canvas(self, width=2, highlightthickness=0)
  42.782 +        spacer.grid(row=0, column=1, rowspan=2, sticky='ns')
  42.783 +        self.hlist = HandlerPanel(self)
  42.784 +        self.hlist.grid(row=0, column=2, sticky='nsew')
  42.785 +        self.flist = FormatterPanel(self)
  42.786 +        self.flist.grid(row=1, column=2, sticky='nsew')
  42.787 +        self.cfg = ConfigPanel(self)
  42.788 +        self.cfg.grid(row=2, column=0, columnspan=2, sticky='w')
  42.789 +        self.filename = None
  42.790 +
  42.791 +        self.rowconfigure(0, weight=1)
  42.792 +        self.columnconfigure(0, weight=1)
  42.793 +        self.columnconfigure(2, weight=1)
  42.794 +
  42.795 +        label = Label(self, text="Copyright (C) 2002 Vinay Sajip. All rights reserved.", foreground='brown')
  42.796 +        label.grid(row=3, column=0, columnspan=2, sticky='w')
  42.797 +
  42.798 +        if len(sys.argv) > 1:
  42.799 +            fn = sys.argv[1]
  42.800 +            try:
  42.801 +                self.loadFile(fn)
  42.802 +            except Exception, e:
  42.803 +                print e
  42.804 +                raise
  42.805 +        else:
  42.806 +            self.onReset(0)
  42.807 +        self.setTitle()
  42.808 +        self.focus_set()
  42.809 +
  42.810 +    def setTitle(self):
  42.811 +        if self.filename:
  42.812 +            s = os.path.split(self.filename)[1]
  42.813 +        else:
  42.814 +            s = "untitled"
  42.815 +        self.winfo_toplevel().title("%s - Python Logging Configurator V%s" % (s, __version__))
  42.816 +
  42.817 +    def loadFile(self, fn):
  42.818 +        self.config = LoggingConfig()
  42.819 +        self.config.read(fn)
  42.820 +        self.filename = fn
  42.821 +        self.llist.setConfig(self.config)
  42.822 +        self.hlist.setConfig(self.config)
  42.823 +        self.flist.setConfig(self.config)
  42.824 +        self.setTitle()
  42.825 +
  42.826 +    def onLoad(self):
  42.827 +        fn = askopenfilename(title="Choose configuration file", filetypes=[("Logging configurations", "*.ini"), ("All files", "*.*")])
  42.828 +        if fn:
  42.829 +            self.loadFile(fn)
  42.830 +
  42.831 +    def onSaveAs(self):
  42.832 +        if self.filename:
  42.833 +            fn = os.path.split(self.filename)[1]
  42.834 +        else:
  42.835 +            fn = DEFAULT_FILENAME
  42.836 +        fn = asksaveasfilename(title="Save configuration as", initialfile=fn, filetypes=[("Logging configurations", "*.ini"), ("All files", "*.*")])
  42.837 +        if fn:
  42.838 +            self.config.save(fn)
  42.839 +            self.filename = fn
  42.840 +            self.setTitle()
  42.841 +
  42.842 +    def onSave(self):
  42.843 +        if not self.filename:
  42.844 +            self.onSaveAs()
  42.845 +        else:
  42.846 +            self.config.save(self.filename)
  42.847 +
  42.848 +    def onReset(self, confirm=1):
  42.849 +        if not confirm:
  42.850 +            doit = 1
  42.851 +        else:
  42.852 +            doit = askyesno("Reset", "Are you sure you want to reset?")
  42.853 +        if doit:
  42.854 +            self.config = LoggingConfig()
  42.855 +            self.llist.setConfig(self.config)
  42.856 +            self.hlist.setConfig(self.config)
  42.857 +            self.flist.setConfig(self.config)
  42.858 +            self.setTitle()
  42.859 +
  42.860 +# -- general properties
  42.861 +
  42.862 +class NameProperty(Property):
  42.863 +    def __init__(self, value=None):
  42.864 +        Property.__init__(self, "name", "Name", value)
  42.865 +
  42.866 +class LevelProperty(Property):
  42.867 +    def __init__(self, value=None):
  42.868 +        Property.__init__(self, "level", "Level", value)
  42.869 +
  42.870 +    def getChoices(self):
  42.871 +        return LOGGING_LEVELS
  42.872 +
  42.873 +# -- formatter properties
  42.874 +
  42.875 +class FormatProperty(Property):
  42.876 +    def __init__(self, value=None):
  42.877 +        Property.__init__(self, "format", "Format", value)
  42.878 +
  42.879 +class DateFormatProperty(Property):
  42.880 +    def __init__(self, value=None):
  42.881 +        Property.__init__(self, "datefmt", "Date Format", value)
  42.882 +
  42.883 +class FormatterProxy(PropertyHolder):
  42.884 +    def __init__(self, config, dict):
  42.885 +        self.config = config
  42.886 +        PropertyHolder.__init__(self, dict)
  42.887 +        prop = NameProperty(dict.get("name", ""))
  42.888 +        self.dict["name"] = prop
  42.889 +        prop = FormatProperty(dict.get("format", "%(asctime)s %(levelname)s %(message)s"))
  42.890 +        self.dict["format"] = prop
  42.891 +        prop = DateFormatProperty(dict.get("datefmt", ""))
  42.892 +        self.dict["datefmt"] = prop
  42.893 +        self.propnames = ["name", "format", "datefmt"]
  42.894 +
  42.895 +    def isReadonly(self, name):
  42.896 +        return name == "name"
  42.897 +
  42.898<