[Python-checkins] r61189 - in python/trunk: Lib/test/test_logging.py Misc/ACKS Misc/NEWS

brett.cannon python-checkins at python.org
Mon Mar 3 01:38:59 CET 2008


Author: brett.cannon
Date: Mon Mar  3 01:38:58 2008
New Revision: 61189

Modified:
   python/trunk/Lib/test/test_logging.py
   python/trunk/Misc/ACKS
   python/trunk/Misc/NEWS
Log:
Refactor test_logging to use unittest. This should finally solve the flakiness
issues.
 
Thanks to Antoine Pitrou for the patch.


Modified: python/trunk/Lib/test/test_logging.py
==============================================================================
--- python/trunk/Lib/test/test_logging.py	(original)
+++ python/trunk/Lib/test/test_logging.py	Mon Mar  3 01:38:58 2008
@@ -1,2016 +1,702 @@
 #!/usr/bin/env python
-"""
-Test 0
-======
-
-Some preliminaries:
->>> import sys
->>> import logging
->>> def nextmessage():
-...    global msgcount
-...    rv = "Message %d" % msgcount
-...    msgcount = msgcount + 1
-...    return rv
-
-Set a few variables, then go through the logger autoconfig and set the default threshold.
->>> msgcount = 0
->>> FINISH_UP = "Finish up, it's closing time. Messages should bear numbers 0 through 24."
->>> logging.basicConfig(stream=sys.stdout)
->>> rootLogger = logging.getLogger("")
->>> rootLogger.setLevel(logging.DEBUG)
-
-Now, create a bunch of loggers, and set their thresholds.
->>> ERR = logging.getLogger("ERR0")
->>> ERR.setLevel(logging.ERROR)
->>> INF = logging.getLogger("INFO0")
->>> INF.setLevel(logging.INFO)
->>> INF_ERR  = logging.getLogger("INFO0.ERR")
->>> INF_ERR.setLevel(logging.ERROR)
->>> DEB = logging.getLogger("DEB0")
->>> DEB.setLevel(logging.DEBUG)
->>> INF_UNDEF = logging.getLogger("INFO0.UNDEF")
->>> INF_ERR_UNDEF = logging.getLogger("INFO0.ERR.UNDEF")
->>> UNDEF = logging.getLogger("UNDEF0")
->>> GRANDCHILD = logging.getLogger("INFO0.BADPARENT.UNDEF")
->>> CHILD = logging.getLogger("INFO0.BADPARENT")
-
-
-And finally, run all the tests.
-
->>> ERR.log(logging.FATAL, nextmessage())
-CRITICAL:ERR0:Message 0
-
->>> ERR.error(nextmessage())
-ERROR:ERR0:Message 1
-
->>> INF.log(logging.FATAL, nextmessage())
-CRITICAL:INFO0:Message 2
-
->>> INF.error(nextmessage())
-ERROR:INFO0:Message 3
-
->>> INF.warn(nextmessage())
-WARNING:INFO0:Message 4
-
->>> INF.info(nextmessage())
-INFO:INFO0:Message 5
-
->>> INF_UNDEF.log(logging.FATAL, nextmessage())
-CRITICAL:INFO0.UNDEF:Message 6
-
->>> INF_UNDEF.error(nextmessage())
-ERROR:INFO0.UNDEF:Message 7
-
->>> INF_UNDEF.warn (nextmessage())
-WARNING:INFO0.UNDEF:Message 8
-
->>> INF_UNDEF.info (nextmessage())
-INFO:INFO0.UNDEF:Message 9
-
->>> INF_ERR.log(logging.FATAL, nextmessage())
-CRITICAL:INFO0.ERR:Message 10
-
->>> INF_ERR.error(nextmessage())
-ERROR:INFO0.ERR:Message 11
-
->>> INF_ERR_UNDEF.log(logging.FATAL, nextmessage())
-CRITICAL:INFO0.ERR.UNDEF:Message 12
-
->>> INF_ERR_UNDEF.error(nextmessage())
-ERROR:INFO0.ERR.UNDEF:Message 13
-
->>> DEB.log(logging.FATAL, nextmessage())
-CRITICAL:DEB0:Message 14
-
->>> DEB.error(nextmessage())
-ERROR:DEB0:Message 15
-
->>> DEB.warn (nextmessage())
-WARNING:DEB0:Message 16
-
->>> DEB.info (nextmessage())
-INFO:DEB0:Message 17
-
->>> DEB.debug(nextmessage())
-DEBUG:DEB0:Message 18
-
->>> UNDEF.log(logging.FATAL, nextmessage())
-CRITICAL:UNDEF0:Message 19
-
->>> UNDEF.error(nextmessage())
-ERROR:UNDEF0:Message 20
-
->>> UNDEF.warn (nextmessage())
-WARNING:UNDEF0:Message 21
-
->>> UNDEF.info (nextmessage())
-INFO:UNDEF0:Message 22
-
->>> GRANDCHILD.log(logging.FATAL, nextmessage())
-CRITICAL:INFO0.BADPARENT.UNDEF:Message 23
-
->>> CHILD.log(logging.FATAL, nextmessage())
-CRITICAL:INFO0.BADPARENT:Message 24
-
-These should not log:
-
->>> ERR.warn(nextmessage())
-
->>> ERR.info(nextmessage())
-
->>> ERR.debug(nextmessage())
-
->>> INF.debug(nextmessage())
-
->>> INF_UNDEF.debug(nextmessage())
-
->>> INF_ERR.warn(nextmessage())
-
->>> INF_ERR.info(nextmessage())
-
->>> INF_ERR.debug(nextmessage())
-
->>> INF_ERR_UNDEF.warn(nextmessage())
-
->>> INF_ERR_UNDEF.info(nextmessage())
-
->>> INF_ERR_UNDEF.debug(nextmessage())
-
->>> INF.info(FINISH_UP)
-INFO:INFO0:Finish up, it's closing time. Messages should bear numbers 0 through 24.
-
-Test 1
-======
-
->>> import sys, logging
->>> logging.basicConfig(stream=sys.stdout)
-
-First, we define our levels. There can be as many as you want - the only
-limitations are that they should be integers, the lowest should be > 0 and
-larger values mean less information being logged. If you need specific
-level values which do not fit into these limitations, you can use a
-mapping dictionary to convert between your application levels and the
-logging system.
-
->>> SILENT      = 10
->>> TACITURN    = 9
->>> TERSE       = 8
->>> EFFUSIVE    = 7
->>> SOCIABLE    = 6
->>> VERBOSE     = 5
->>> TALKATIVE   = 4
->>> GARRULOUS   = 3
->>> CHATTERBOX  = 2
->>> BORING      = 1
->>> LEVEL_RANGE = range(BORING, SILENT + 1)
-
-
-Next, we define names for our levels. You don't need to do this - in which
-  case the system will use "Level n" to denote the text for the level.
-'
-
-
->>> my_logging_levels = {
-...     SILENT      : 'SILENT',
-...     TACITURN    : 'TACITURN',
-...     TERSE       : 'TERSE',
-...     EFFUSIVE    : 'EFFUSIVE',
-...     SOCIABLE    : 'SOCIABLE',
-...     VERBOSE     : 'VERBOSE',
-...     TALKATIVE   : 'TALKATIVE',
-...     GARRULOUS   : 'GARRULOUS',
-...     CHATTERBOX  : 'CHATTERBOX',
-...     BORING      : 'BORING',
-...     }
-
-
-Now, to demonstrate filtering: suppose for some perverse reason we only
-want to print out all except GARRULOUS messages. We create a filter for
-this purpose...
-
->>> class SpecificLevelFilter(logging.Filter):
-...     def __init__(self, lvl):
-...         self.level = lvl
-...
-...     def filter(self, record):
-...         return self.level != record.levelno
-
->>> class GarrulousFilter(SpecificLevelFilter):
-...     def __init__(self):
-...         SpecificLevelFilter.__init__(self, GARRULOUS)
-
-
-Now, demonstrate filtering at the logger. This time, use a filter
-which excludes SOCIABLE and TACITURN messages. Note that GARRULOUS events
-are still excluded.
-
-
->>> class VerySpecificFilter(logging.Filter):
-...     def filter(self, record):
-...         return record.levelno not in [SOCIABLE, TACITURN]
-
->>> SHOULD1 = "This should only be seen at the '%s' logging level (or lower)"
-
-Configure the logger, and tell the logging system to associate names with our levels.
->>> logging.basicConfig(stream=sys.stdout)
->>> rootLogger = logging.getLogger("")
->>> rootLogger.setLevel(logging.DEBUG)
->>> for lvl in my_logging_levels.keys():
-...    logging.addLevelName(lvl, my_logging_levels[lvl])
->>> log = logging.getLogger("")
->>> hdlr = log.handlers[0]
->>> from test_logging import message
-
-Set the logging level to each different value and call the utility
-function to log events. In the output, you should see that each time
-round the loop, the number of logging events which are actually output
-decreases.
-
->>> log.setLevel(1)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-BORING:root:This should only be seen at the '1' logging level (or lower)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-CHATTERBOX:root:This should only be seen at the '2' logging level (or lower)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-GARRULOUS:root:This should only be seen at the '3' logging level (or lower)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(2)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-CHATTERBOX:root:This should only be seen at the '2' logging level (or lower)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-GARRULOUS:root:This should only be seen at the '3' logging level (or lower)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(3)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-GARRULOUS:root:This should only be seen at the '3' logging level (or lower)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(4)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(5)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
-
->>> log.setLevel(6)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(7)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(8)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(9)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(10)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> hdlr.setLevel(SOCIABLE)
-
->>> log.setLevel(1)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(2)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(3)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(4)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(5)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(6)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(7)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(8)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(9)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(10)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>>
-
->>> hdlr.setLevel(0)
-
->>> garr = GarrulousFilter()
-
->>> hdlr.addFilter(garr)
-
->>> log.setLevel(1)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-BORING:root:This should only be seen at the '1' logging level (or lower)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-CHATTERBOX:root:This should only be seen at the '2' logging level (or lower)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(2)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-CHATTERBOX:root:This should only be seen at the '2' logging level (or lower)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(3)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(4)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(5)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.setLevel(6)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-SOCIABLE:root:This should only be seen at the '6' logging level (or lower)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(7)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(8)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(9)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-TACITURN:root:This should only be seen at the '9' logging level (or lower)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(10)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> spec = VerySpecificFilter()
-
->>> log.addFilter(spec)
-
->>> log.setLevel(1)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-BORING:root:This should only be seen at the '1' logging level (or lower)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-CHATTERBOX:root:This should only be seen at the '2' logging level (or lower)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(2)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-CHATTERBOX:root:This should only be seen at the '2' logging level (or lower)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(3)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(4)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-TALKATIVE:root:This should only be seen at the '4' logging level (or lower)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(5)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
+#
+# Copyright 2001-2004 by Vinay Sajip. All Rights Reserved.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose and without fee is hereby granted,
+# provided that the above copyright notice appear in all copies and that
+# both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of Vinay Sajip
+# not be used in advertising or publicity pertaining to distribution
+# of the software without specific, written prior permission.
+# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
+"""Test harness for the logging module. Run all tests.
 
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-VERBOSE:root:This should only be seen at the '5' logging level (or lower)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(6)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(7)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-EFFUSIVE:root:This should only be seen at the '7' logging level (or lower)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(8)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-TERSE:root:This should only be seen at the '8' logging level (or lower)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(9)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(10)
-
->>> log.log(1, "This should only be seen at the '%s' logging level (or lower)", BORING)
-
->>> log.log(2, "This should only be seen at the '%s' logging level (or lower)", CHATTERBOX)
-
->>> log.log(3, "This should only be seen at the '%s' logging level (or lower)", GARRULOUS)
-
->>> log.log(4, "This should only be seen at the '%s' logging level (or lower)", TALKATIVE)
-
->>> log.log(5, "This should only be seen at the '%s' logging level (or lower)", VERBOSE)
-
->>> log.log(6, "This should only be seen at the '%s' logging level (or lower)", SOCIABLE)
-
->>> log.log(7, "This should only be seen at the '%s' logging level (or lower)", EFFUSIVE)
-
->>> log.log(8, "This should only be seen at the '%s' logging level (or lower)", TERSE)
-
->>> log.log(9, "This should only be seen at the '%s' logging level (or lower)", TACITURN)
-
->>> log.log(10, "This should only be seen at the '%s' logging level (or lower)", SILENT)
-SILENT:root:This should only be seen at the '10' logging level (or lower)
-
->>> log.setLevel(0)
-
->>> log.removeFilter(spec)
-
->>> hdlr.removeFilter(garr)
-
->>> logging.addLevelName(logging.DEBUG, "DEBUG")
-
-
-Test 2
-======
-Test memory handlers. These are basically buffers for log messages: they take so many messages, and then print them all.
-
->>> import logging.handlers
-
->>> sys.stderr = sys.stdout
->>> logger = logging.getLogger("")
->>> sh = logger.handlers[0]
->>> sh.close()
->>> logger.removeHandler(sh)
->>> mh = logging.handlers.MemoryHandler(10,logging.WARNING, sh)
->>> logger.setLevel(logging.DEBUG)
->>> logger.addHandler(mh)
-
->>> logger.debug("Debug message")
-
--- logging at INFO, nothing should be seen yet --
-
->>> logger.info("Info message")
-
--- logging at WARNING, 3 messages should be seen --
-
->>> logger.warn("Warn message")
-DEBUG:root:Debug message
-INFO:root:Info message
-WARNING:root:Warn message
-
->>> logger.info("Info index = 0")
-
->>> logger.info("Info index = 1")
-
->>> logger.info("Info index = 2")
-
->>> logger.info("Info index = 3")
-
->>> logger.info("Info index = 4")
-
->>> logger.info("Info index = 5")
-
->>> logger.info("Info index = 6")
-
->>> logger.info("Info index = 7")
-
->>> logger.info("Info index = 8")
-
->>> logger.info("Info index = 9")
-INFO:root:Info index = 0
-INFO:root:Info index = 1
-INFO:root:Info index = 2
-INFO:root:Info index = 3
-INFO:root:Info index = 4
-INFO:root:Info index = 5
-INFO:root:Info index = 6
-INFO:root:Info index = 7
-INFO:root:Info index = 8
-INFO:root:Info index = 9
-
->>> logger.info("Info index = 10")
-
->>> logger.info("Info index = 11")
-
->>> logger.info("Info index = 12")
-
->>> logger.info("Info index = 13")
-
->>> logger.info("Info index = 14")
-
->>> logger.info("Info index = 15")
-
->>> logger.info("Info index = 16")
-
->>> logger.info("Info index = 17")
-
->>> logger.info("Info index = 18")
-
->>> logger.info("Info index = 19")
-INFO:root:Info index = 10
-INFO:root:Info index = 11
-INFO:root:Info index = 12
-INFO:root:Info index = 13
-INFO:root:Info index = 14
-INFO:root:Info index = 15
-INFO:root:Info index = 16
-INFO:root:Info index = 17
-INFO:root:Info index = 18
-INFO:root:Info index = 19
-
->>> logger.info("Info index = 20")
-
->>> logger.info("Info index = 21")
-
->>> logger.info("Info index = 22")
-
->>> logger.info("Info index = 23")
-
->>> logger.info("Info index = 24")
-
->>> logger.info("Info index = 25")
-
->>> logger.info("Info index = 26")
-
->>> logger.info("Info index = 27")
-
->>> logger.info("Info index = 28")
-
->>> logger.info("Info index = 29")
-INFO:root:Info index = 20
-INFO:root:Info index = 21
-INFO:root:Info index = 22
-INFO:root:Info index = 23
-INFO:root:Info index = 24
-INFO:root:Info index = 25
-INFO:root:Info index = 26
-INFO:root:Info index = 27
-INFO:root:Info index = 28
-INFO:root:Info index = 29
-
->>> logger.info("Info index = 30")
-
->>> logger.info("Info index = 31")
-
->>> logger.info("Info index = 32")
-
->>> logger.info("Info index = 33")
-
->>> logger.info("Info index = 34")
-
->>> logger.info("Info index = 35")
-
->>> logger.info("Info index = 36")
-
->>> logger.info("Info index = 37")
-
->>> logger.info("Info index = 38")
-
->>> logger.info("Info index = 39")
-INFO:root:Info index = 30
-INFO:root:Info index = 31
-INFO:root:Info index = 32
-INFO:root:Info index = 33
-INFO:root:Info index = 34
-INFO:root:Info index = 35
-INFO:root:Info index = 36
-INFO:root:Info index = 37
-INFO:root:Info index = 38
-INFO:root:Info index = 39
-
->>> logger.info("Info index = 40")
-
->>> logger.info("Info index = 41")
-
->>> logger.info("Info index = 42")
-
->>> logger.info("Info index = 43")
-
->>> logger.info("Info index = 44")
-
->>> logger.info("Info index = 45")
-
->>> logger.info("Info index = 46")
-
->>> logger.info("Info index = 47")
-
->>> logger.info("Info index = 48")
-
->>> logger.info("Info index = 49")
-INFO:root:Info index = 40
-INFO:root:Info index = 41
-INFO:root:Info index = 42
-INFO:root:Info index = 43
-INFO:root:Info index = 44
-INFO:root:Info index = 45
-INFO:root:Info index = 46
-INFO:root:Info index = 47
-INFO:root:Info index = 48
-INFO:root:Info index = 49
-
->>> logger.info("Info index = 50")
-
->>> logger.info("Info index = 51")
-
->>> logger.info("Info index = 52")
-
->>> logger.info("Info index = 53")
-
->>> logger.info("Info index = 54")
-
->>> logger.info("Info index = 55")
-
->>> logger.info("Info index = 56")
-
->>> logger.info("Info index = 57")
-
->>> logger.info("Info index = 58")
-
->>> logger.info("Info index = 59")
-INFO:root:Info index = 50
-INFO:root:Info index = 51
-INFO:root:Info index = 52
-INFO:root:Info index = 53
-INFO:root:Info index = 54
-INFO:root:Info index = 55
-INFO:root:Info index = 56
-INFO:root:Info index = 57
-INFO:root:Info index = 58
-INFO:root:Info index = 59
-
->>> logger.info("Info index = 60")
-
->>> logger.info("Info index = 61")
-
->>> logger.info("Info index = 62")
-
->>> logger.info("Info index = 63")
-
->>> logger.info("Info index = 64")
-
->>> logger.info("Info index = 65")
-
->>> logger.info("Info index = 66")
-
->>> logger.info("Info index = 67")
-
->>> logger.info("Info index = 68")
-
->>> logger.info("Info index = 69")
-INFO:root:Info index = 60
-INFO:root:Info index = 61
-INFO:root:Info index = 62
-INFO:root:Info index = 63
-INFO:root:Info index = 64
-INFO:root:Info index = 65
-INFO:root:Info index = 66
-INFO:root:Info index = 67
-INFO:root:Info index = 68
-INFO:root:Info index = 69
-
->>> logger.info("Info index = 70")
-
->>> logger.info("Info index = 71")
-
->>> logger.info("Info index = 72")
-
->>> logger.info("Info index = 73")
-
->>> logger.info("Info index = 74")
-
->>> logger.info("Info index = 75")
-
->>> logger.info("Info index = 76")
-
->>> logger.info("Info index = 77")
-
->>> logger.info("Info index = 78")
-
->>> logger.info("Info index = 79")
-INFO:root:Info index = 70
-INFO:root:Info index = 71
-INFO:root:Info index = 72
-INFO:root:Info index = 73
-INFO:root:Info index = 74
-INFO:root:Info index = 75
-INFO:root:Info index = 76
-INFO:root:Info index = 77
-INFO:root:Info index = 78
-INFO:root:Info index = 79
-
->>> logger.info("Info index = 80")
-
->>> logger.info("Info index = 81")
-
->>> logger.info("Info index = 82")
-
->>> logger.info("Info index = 83")
-
->>> logger.info("Info index = 84")
-
->>> logger.info("Info index = 85")
-
->>> logger.info("Info index = 86")
-
->>> logger.info("Info index = 87")
-
->>> logger.info("Info index = 88")
-
->>> logger.info("Info index = 89")
-INFO:root:Info index = 80
-INFO:root:Info index = 81
-INFO:root:Info index = 82
-INFO:root:Info index = 83
-INFO:root:Info index = 84
-INFO:root:Info index = 85
-INFO:root:Info index = 86
-INFO:root:Info index = 87
-INFO:root:Info index = 88
-INFO:root:Info index = 89
-
->>> logger.info("Info index = 90")
-
->>> logger.info("Info index = 91")
-
->>> logger.info("Info index = 92")
-
->>> logger.info("Info index = 93")
-
->>> logger.info("Info index = 94")
-
->>> logger.info("Info index = 95")
-
->>> logger.info("Info index = 96")
-
->>> logger.info("Info index = 97")
-
->>> logger.info("Info index = 98")
-
->>> logger.info("Info index = 99")
-INFO:root:Info index = 90
-INFO:root:Info index = 91
-INFO:root:Info index = 92
-INFO:root:Info index = 93
-INFO:root:Info index = 94
-INFO:root:Info index = 95
-INFO:root:Info index = 96
-INFO:root:Info index = 97
-INFO:root:Info index = 98
-INFO:root:Info index = 99
-
->>> logger.info("Info index = 100")
-
->>> logger.info("Info index = 101")
-
->>> mh.close()
-INFO:root:Info index = 100
-INFO:root:Info index = 101
-
->>> logger.removeHandler(mh)
->>> logger.addHandler(sh)
-
-
-
-Test 3
-======
-
->>> import sys, logging
->>> sys.stderr = sys
->>> logging.basicConfig()
->>> FILTER = "a.b"
->>> root = logging.getLogger()
->>> root.setLevel(logging.DEBUG)
->>> hand = root.handlers[0]
-
->>> logging.getLogger("a").info("Info 1")
-INFO:a:Info 1
-
->>> logging.getLogger("a.b").info("Info 2")
-INFO:a.b:Info 2
-
->>> logging.getLogger("a.c").info("Info 3")
-INFO:a.c:Info 3
-
->>> logging.getLogger("a.b.c").info("Info 4")
-INFO:a.b.c:Info 4
-
->>> logging.getLogger("a.b.c.d").info("Info 5")
-INFO:a.b.c.d:Info 5
-
->>> logging.getLogger("a.bb.c").info("Info 6")
-INFO:a.bb.c:Info 6
-
->>> logging.getLogger("b").info("Info 7")
-INFO:b:Info 7
-
->>> logging.getLogger("b.a").info("Info 8")
-INFO:b.a:Info 8
-
->>> logging.getLogger("c.a.b").info("Info 9")
-INFO:c.a.b:Info 9
-
->>> logging.getLogger("a.bb").info("Info 10")
-INFO:a.bb:Info 10
-
-Filtered with 'a.b'...
-
->>> filt = logging.Filter(FILTER)
-
->>> hand.addFilter(filt)
-
->>> logging.getLogger("a").info("Info 1")
-
->>> logging.getLogger("a.b").info("Info 2")
-INFO:a.b:Info 2
-
->>> logging.getLogger("a.c").info("Info 3")
-
->>> logging.getLogger("a.b.c").info("Info 4")
-INFO:a.b.c:Info 4
+Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
+"""
 
->>> logging.getLogger("a.b.c.d").info("Info 5")
-INFO:a.b.c.d:Info 5
+import logging
+import logging.handlers
+import logging.config
+
+import copy
+import cPickle
+import cStringIO
+import gc
+import os
+import re
+import select
+import socket
+from SocketServer import ThreadingTCPServer, StreamRequestHandler
+import string
+import struct
+import sys
+import tempfile
+from test.test_support import captured_stdout, run_with_locale, run_unittest
+import textwrap
+import threading
+import time
+import types
+import unittest
+import weakref
+
+
+class BaseTest(unittest.TestCase):
+
+    """Base class for logging tests."""
+
+    log_format = "%(name)s -> %(levelname)s: %(message)s"
+    expected_log_pat = r"^([\w.]+) -> ([\w]+): ([\d]+)$"
+    message_num = 0
+
+    def setUp(self):
+        """Setup the default logging stream to an internal StringIO instance,
+        so that we can examine log output as we want."""
+        logger_dict = logging.getLogger().manager.loggerDict
+        logging._acquireLock()
+        try:
+            self.saved_handlers = logging._handlers.copy()
+            self.saved_handler_list = logging._handlerList[:]
+            self.saved_loggers = logger_dict.copy()
+            self.saved_level_names = logging._levelNames.copy()
+        finally:
+            logging._releaseLock()
 
->>> logging.getLogger("a.bb.c").info("Info 6")
+        self.root_logger = logging.getLogger("")
+        self.original_logging_level = self.root_logger.getEffectiveLevel()
 
->>> logging.getLogger("b").info("Info 7")
+        self.stream = cStringIO.StringIO()
+        self.root_logger.setLevel(logging.DEBUG)
+        self.root_hdlr = logging.StreamHandler(self.stream)
+        self.root_formatter = logging.Formatter(self.log_format)
+        self.root_hdlr.setFormatter(self.root_formatter)
+        self.root_logger.addHandler(self.root_hdlr)
+
+    def tearDown(self):
+        """Remove our logging stream, and restore the original logging
+        level."""
+        self.stream.close()
+        self.root_logger.removeHandler(self.root_hdlr)
+        self.root_logger.setLevel(self.original_logging_level)
+        logging._acquireLock()
+        try:
+            logging._levelNames.clear()
+            logging._levelNames.update(self.saved_level_names)
+            logging._handlers.clear()
+            logging._handlers.update(self.saved_handlers)
+            logging._handlerList[:] = self.saved_handler_list
+            loggerDict = logging.getLogger().manager.loggerDict
+            loggerDict.clear()
+            loggerDict.update(self.saved_loggers)
+        finally:
+            logging._releaseLock()
 
->>> logging.getLogger("b.a").info("Info 8")
+    def assert_log_lines(self, expected_values, stream=None):
+        """Match the collected log lines against the regular expression
+        self.expected_log_pat, and compare the extracted group values to
+        the expected_values list of tuples."""
+        stream = stream or self.stream
+        pat = re.compile(self.expected_log_pat)
+        try:
+            stream.reset()
+            actual_lines = stream.readlines()
+        except AttributeError:
+            # StringIO.StringIO lacks a reset() method.
+            actual_lines = stream.getvalue().splitlines()
+        self.assertEquals(len(actual_lines), len(expected_values))
+        for actual, expected in zip(actual_lines, expected_values):
+            match = pat.search(actual)
+            if not match:
+                self.fail("Log line does not match expected pattern:\n" +
+                            actual)
+            self.assertEquals(tuple(match.groups()), expected)
+        s = stream.read()
+        if s:
+            self.fail("Remaining output at end of log stream:\n" + s)
+
+    def next_message(self):
+        """Generate a message consisting solely of an auto-incrementing
+        integer."""
+        self.message_num += 1
+        return "%d" % self.message_num
+
+
+class BuiltinLevelsTest(BaseTest):
+    """Test builtin levels and their inheritance."""
+
+    def test_flat(self):
+        #Logging levels in a flat logger namespace.
+        m = self.next_message
+
+        ERR = logging.getLogger("ERR")
+        ERR.setLevel(logging.ERROR)
+        INF = logging.getLogger("INF")
+        INF.setLevel(logging.INFO)
+        DEB = logging.getLogger("DEB")
+        DEB.setLevel(logging.DEBUG)
+
+        # These should log.
+        ERR.log(logging.CRITICAL, m())
+        ERR.error(m())
+
+        INF.log(logging.CRITICAL, m())
+        INF.error(m())
+        INF.warn(m())
+        INF.info(m())
+
+        DEB.log(logging.CRITICAL, m())
+        DEB.error(m())
+        DEB.warn (m())
+        DEB.info (m())
+        DEB.debug(m())
+
+        # These should not log.
+        ERR.warn(m())
+        ERR.info(m())
+        ERR.debug(m())
+
+        INF.debug(m())
+
+        self.assert_log_lines([
+            ('ERR', 'CRITICAL', '1'),
+            ('ERR', 'ERROR', '2'),
+            ('INF', 'CRITICAL', '3'),
+            ('INF', 'ERROR', '4'),
+            ('INF', 'WARNING', '5'),
+            ('INF', 'INFO', '6'),
+            ('DEB', 'CRITICAL', '7'),
+            ('DEB', 'ERROR', '8'),
+            ('DEB', 'WARNING', '9'),
+            ('DEB', 'INFO', '10'),
+            ('DEB', 'DEBUG', '11'),
+        ])
+
+    def test_nested_explicit(self):
+        # Logging levels in a nested namespace, all explicitly set.
+        m = self.next_message
+
+        INF = logging.getLogger("INF")
+        INF.setLevel(logging.INFO)
+        INF_ERR  = logging.getLogger("INF.ERR")
+        INF_ERR.setLevel(logging.ERROR)
+
+        # These should log.
+        INF_ERR.log(logging.CRITICAL, m())
+        INF_ERR.error(m())
+
+        # These should not log.
+        INF_ERR.warn(m())
+        INF_ERR.info(m())
+        INF_ERR.debug(m())
+
+        self.assert_log_lines([
+            ('INF.ERR', 'CRITICAL', '1'),
+            ('INF.ERR', 'ERROR', '2'),
+        ])
+
+    def test_nested_inherited(self):
+        #Logging levels in a nested namespace, inherited from parent loggers.
+        m = self.next_message
+
+        INF = logging.getLogger("INF")
+        INF.setLevel(logging.INFO)
+        INF_ERR  = logging.getLogger("INF.ERR")
+        INF_ERR.setLevel(logging.ERROR)
+        INF_UNDEF = logging.getLogger("INF.UNDEF")
+        INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
+        UNDEF = logging.getLogger("UNDEF")
+
+        # These should log.
+        INF_UNDEF.log(logging.CRITICAL, m())
+        INF_UNDEF.error(m())
+        INF_UNDEF.warn(m())
+        INF_UNDEF.info(m())
+        INF_ERR_UNDEF.log(logging.CRITICAL, m())
+        INF_ERR_UNDEF.error(m())
+
+        # These should not log.
+        INF_UNDEF.debug(m())
+        INF_ERR_UNDEF.warn(m())
+        INF_ERR_UNDEF.info(m())
+        INF_ERR_UNDEF.debug(m())
+
+        self.assert_log_lines([
+            ('INF.UNDEF', 'CRITICAL', '1'),
+            ('INF.UNDEF', 'ERROR', '2'),
+            ('INF.UNDEF', 'WARNING', '3'),
+            ('INF.UNDEF', 'INFO', '4'),
+            ('INF.ERR.UNDEF', 'CRITICAL', '5'),
+            ('INF.ERR.UNDEF', 'ERROR', '6'),
+        ])
+
+    def test_nested_with_virtual_parent(self):
+        # Logging levels when some parent does not exist yet.
+        m = self.next_message
+
+        INF = logging.getLogger("INF")
+        GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
+        CHILD = logging.getLogger("INF.BADPARENT")
+        INF.setLevel(logging.INFO)
+
+        # These should log.
+        GRANDCHILD.log(logging.FATAL, m())
+        GRANDCHILD.info(m())
+        CHILD.log(logging.FATAL, m())
+        CHILD.info(m())
+
+        # These should not log.
+        GRANDCHILD.debug(m())
+        CHILD.debug(m())
+
+        self.assert_log_lines([
+            ('INF.BADPARENT.UNDEF', 'CRITICAL', '1'),
+            ('INF.BADPARENT.UNDEF', 'INFO', '2'),
+            ('INF.BADPARENT', 'CRITICAL', '3'),
+            ('INF.BADPARENT', 'INFO', '4'),
+        ])
+
+
+class BasicFilterTest(BaseTest):
+
+    """Test the bundled Filter class."""
+
+    def test_filter(self):
+        # Only messages satisfying the specified criteria pass through the
+        #  filter.
+        filter_ = logging.Filter("spam.eggs")
+        handler = self.root_logger.handlers[0]
+        try:
+            handler.addFilter(filter_)
+            spam = logging.getLogger("spam")
+            spam_eggs = logging.getLogger("spam.eggs")
+            spam_eggs_fish = logging.getLogger("spam.eggs.fish")
+            spam_bakedbeans = logging.getLogger("spam.bakedbeans")
+
+            spam.info(self.next_message())
+            spam_eggs.info(self.next_message())  # Good.
+            spam_eggs_fish.info(self.next_message())  # Good.
+            spam_bakedbeans.info(self.next_message())
+
+            self.assert_log_lines([
+                ('spam.eggs', 'INFO', '2'),
+                ('spam.eggs.fish', 'INFO', '3'),
+            ])
+        finally:
+            handler.removeFilter(filter_)
 
->>> logging.getLogger("c.a.b").info("Info 9")
 
->>> logging.getLogger("a.bb").info("Info 10")
+#
+#   First, we define our levels. There can be as many as you want - the only
+#     limitations are that they should be integers, the lowest should be > 0 and
+#   larger values mean less information being logged. If you need specific
+#   level values which do not fit into these limitations, you can use a
+#   mapping dictionary to convert between your application levels and the
+#   logging system.
+#
+SILENT      = 120
+TACITURN    = 119
+TERSE       = 118
+EFFUSIVE    = 117
+SOCIABLE    = 116
+VERBOSE     = 115
+TALKATIVE   = 114
+GARRULOUS   = 113
+CHATTERBOX  = 112
+BORING      = 111
+
+LEVEL_RANGE = range(BORING, SILENT + 1)
+
+#
+#   Next, we define names for our levels. You don't need to do this - in which
+#   case the system will use "Level n" to denote the text for the level.
+#
+my_logging_levels = {
+    SILENT      : 'Silent',
+    TACITURN    : 'Taciturn',
+    TERSE       : 'Terse',
+    EFFUSIVE    : 'Effusive',
+    SOCIABLE    : 'Sociable',
+    VERBOSE     : 'Verbose',
+    TALKATIVE   : 'Talkative',
+    GARRULOUS   : 'Garrulous',
+    CHATTERBOX  : 'Chatterbox',
+    BORING      : 'Boring',
+}
+
+class GarrulousFilter(logging.Filter):
+
+    """A filter which blocks garrulous messages."""
+
+    def filter(self, record):
+        return record.levelno != GARRULOUS
+
+class VerySpecificFilter(logging.Filter):
+
+    """A filter which blocks sociable and taciturn messages."""
+
+    def filter(self, record):
+        return record.levelno not in [SOCIABLE, TACITURN]
+
+
+class CustomLevelsAndFiltersTest(BaseTest):
+
+    """Test various filtering possibilities with custom logging levels."""
+
+    # Skip the logger name group.
+    expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
+
+    def setUp(self):
+        BaseTest.setUp(self)
+        for k, v in my_logging_levels.items():
+            logging.addLevelName(k, v)
+
+    def log_at_all_levels(self, logger):
+        for lvl in LEVEL_RANGE:
+            logger.log(lvl, self.next_message())
+
+    def test_logger_filter(self):
+        # Filter at logger level.
+        self.root_logger.setLevel(VERBOSE)
+        # Levels >= 'Verbose' are good.
+        self.log_at_all_levels(self.root_logger)
+        self.assert_log_lines([
+            ('Verbose', '5'),
+            ('Sociable', '6'),
+            ('Effusive', '7'),
+            ('Terse', '8'),
+            ('Taciturn', '9'),
+            ('Silent', '10'),
+        ])
+
+    def test_handler_filter(self):
+        # Filter at handler level.
+        self.root_logger.handlers[0].setLevel(SOCIABLE)
+        try:
+            # Levels >= 'Sociable' are good.
+            self.log_at_all_levels(self.root_logger)
+            self.assert_log_lines([
+                ('Sociable', '6'),
+                ('Effusive', '7'),
+                ('Terse', '8'),
+                ('Taciturn', '9'),
+                ('Silent', '10'),
+            ])
+        finally:
+            self.root_logger.handlers[0].setLevel(logging.NOTSET)
 
->>> hand.removeFilter(filt)
+    def test_specific_filters(self):
+        # Set a specific filter object on the handler, and then add another
+        #  filter object on the logger itself.
+        handler = self.root_logger.handlers[0]
+        specific_filter = None
+        garr = GarrulousFilter()
+        handler.addFilter(garr)
+        try:
+            self.log_at_all_levels(self.root_logger)
+            first_lines = [
+                # Notice how 'Garrulous' is missing
+                ('Boring', '1'),
+                ('Chatterbox', '2'),
+                ('Talkative', '4'),
+                ('Verbose', '5'),
+                ('Sociable', '6'),
+                ('Effusive', '7'),
+                ('Terse', '8'),
+                ('Taciturn', '9'),
+                ('Silent', '10'),
+            ]
+            self.assert_log_lines(first_lines)
+
+            specific_filter = VerySpecificFilter()
+            self.root_logger.addFilter(specific_filter)
+            self.log_at_all_levels(self.root_logger)
+            self.assert_log_lines(first_lines + [
+                # Not only 'Garrulous' is still missing, but also 'Sociable'
+                # and 'Taciturn'
+                ('Boring', '11'),
+                ('Chatterbox', '12'),
+                ('Talkative', '14'),
+                ('Verbose', '15'),
+                ('Effusive', '17'),
+                ('Terse', '18'),
+                ('Silent', '20'),
+        ])
+        finally:
+            if specific_filter:
+                self.root_logger.removeFilter(specific_filter)
+            handler.removeFilter(garr)
+
+
+class MemoryHandlerTest(BaseTest):
+
+    """Tests for the MemoryHandler."""
+
+    # Do not bother with a logger name group.
+    expected_log_pat = r"^[\w.]+ -> ([\w]+): ([\d]+)$"
+
+    def setUp(self):
+        BaseTest.setUp(self)
+        self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
+                                                        self.root_hdlr)
+        self.mem_logger = logging.getLogger('mem')
+        self.mem_logger.propagate = 0
+        self.mem_logger.addHandler(self.mem_hdlr)
+
+    def tearDown(self):
+        self.mem_hdlr.close()
+
+    def test_flush(self):
+        # The memory handler flushes to its target handler based on specific
+        #  criteria (message count and message level).
+        self.mem_logger.debug(self.next_message())
+        self.assert_log_lines([])
+        self.mem_logger.info(self.next_message())
+        self.assert_log_lines([])
+        # This will flush because the level is >= logging.WARNING
+        self.mem_logger.warn(self.next_message())
+        lines = [
+            ('DEBUG', '1'),
+            ('INFO', '2'),
+            ('WARNING', '3'),
+        ]
+        self.assert_log_lines(lines)
+        for n in (4, 14):
+            for i in range(9):
+                self.mem_logger.debug(self.next_message())
+            self.assert_log_lines(lines)
+            # This will flush because it's the 10th message since the last
+            #  flush.
+            self.mem_logger.debug(self.next_message())
+            lines = lines + [('DEBUG', str(i)) for i in range(n, n + 10)]
+            self.assert_log_lines(lines)
 
+        self.mem_logger.debug(self.next_message())
+        self.assert_log_lines(lines)
 
-Test 4
-======
->>> import sys, logging, logging.handlers, string
->>> import tempfile, logging.config, os, test.test_support
->>> sys.stderr = sys.stdout
 
->>> from test_logging import config0, config1
+class ExceptionFormatter(logging.Formatter):
+    """A special exception formatter."""
+    def formatException(self, ei):
+        return "Got a [%s]" % ei[0].__name__
 
-config2 has a subtle configuration error that should be reported
->>> config2 = string.replace(config1, "sys.stdout", "sys.stbout")
 
-config3 has a less subtle configuration error
->>> config3 = string.replace(config1, "formatter=form1", "formatter=misspelled_name")
+class ConfigFileTest(BaseTest):
 
->>> def test4(conf):
-...     loggerDict = logging.getLogger().manager.loggerDict
-...     logging._acquireLock()
-...     try:
-...         saved_handlers = logging._handlers.copy()
-...         saved_handler_list = logging._handlerList[:]
-...         saved_loggers = loggerDict.copy()
-...     finally:
-...         logging._releaseLock()
-...     try:
-...         fn = test.test_support.TESTFN
-...         f = open(fn, "w")
-...         f.write(conf)
-...         f.close()
-...         try:
-...             logging.config.fileConfig(fn)
-...             #call again to make sure cleanup is correct
-...             logging.config.fileConfig(fn)
-...         except:
-...             t = sys.exc_info()[0]
-...             message(str(t))
-...         else:
-...             message('ok.')
-...             os.remove(fn)
-...     finally:
-...         logging._acquireLock()
-...         try:
-...             logging._handlers.clear()
-...             logging._handlers.update(saved_handlers)
-...             logging._handlerList[:] = saved_handler_list
-...             loggerDict = logging.getLogger().manager.loggerDict
-...             loggerDict.clear()
-...             loggerDict.update(saved_loggers)
-...         finally:
-...             logging._releaseLock()
+    """Reading logging config from a .ini-style config file."""
 
->>> test4(config0)
-ok.
+    expected_log_pat = r"^([\w]+) \+\+ ([\w]+)$"
 
->>> test4(config1)
-ok.
+    # config0 is a standard configuration.
+    config0 = """
+    [loggers]
+    keys=root
 
->>> test4(config2)
-<type 'exceptions.AttributeError'>
+    [handlers]
+    keys=hand1
 
->>> test4(config3)
-<type 'exceptions.KeyError'>
+    [formatters]
+    keys=form1
 
->>> import test_logging
->>> test_logging.test5()
-ERROR:root:just testing
-<type 'exceptions.KeyError'>... Don't panic!
+    [logger_root]
+    level=WARNING
+    handlers=hand1
 
+    [handler_hand1]
+    class=StreamHandler
+    level=NOTSET
+    formatter=form1
+    args=(sys.stdout,)
 
-Test Main
-=========
->>> import select
->>> import os, sys, string, struct, types, cPickle, cStringIO
->>> import socket, tempfile, threading, time
->>> import logging, logging.handlers, logging.config
->>> import test_logging
+    [formatter_form1]
+    format=%(levelname)s ++ %(message)s
+    datefmt=
+    """
 
->>> test_logging.test_main_inner()
-ERR -> CRITICAL: Message 0 (via logrecv.tcp.ERR)
-ERR -> ERROR: Message 1 (via logrecv.tcp.ERR)
-INF -> CRITICAL: Message 2 (via logrecv.tcp.INF)
-INF -> ERROR: Message 3 (via logrecv.tcp.INF)
-INF -> WARNING: Message 4 (via logrecv.tcp.INF)
-INF -> INFO: Message 5 (via logrecv.tcp.INF)
-INF.UNDEF -> CRITICAL: Message 6 (via logrecv.tcp.INF.UNDEF)
-INF.UNDEF -> ERROR: Message 7 (via logrecv.tcp.INF.UNDEF)
-INF.UNDEF -> WARNING: Message 8 (via logrecv.tcp.INF.UNDEF)
-INF.UNDEF -> INFO: Message 9 (via logrecv.tcp.INF.UNDEF)
-INF.ERR -> CRITICAL: Message 10 (via logrecv.tcp.INF.ERR)
-INF.ERR -> ERROR: Message 11 (via logrecv.tcp.INF.ERR)
-INF.ERR.UNDEF -> CRITICAL: Message 12 (via logrecv.tcp.INF.ERR.UNDEF)
-INF.ERR.UNDEF -> ERROR: Message 13 (via logrecv.tcp.INF.ERR.UNDEF)
-DEB -> CRITICAL: Message 14 (via logrecv.tcp.DEB)
-DEB -> ERROR: Message 15 (via logrecv.tcp.DEB)
-DEB -> WARNING: Message 16 (via logrecv.tcp.DEB)
-DEB -> INFO: Message 17 (via logrecv.tcp.DEB)
-DEB -> DEBUG: Message 18 (via logrecv.tcp.DEB)
-UNDEF -> CRITICAL: Message 19 (via logrecv.tcp.UNDEF)
-UNDEF -> ERROR: Message 20 (via logrecv.tcp.UNDEF)
-UNDEF -> WARNING: Message 21 (via logrecv.tcp.UNDEF)
-UNDEF -> INFO: Message 22 (via logrecv.tcp.UNDEF)
-INF.BADPARENT.UNDEF -> CRITICAL: Message 23 (via logrecv.tcp.INF.BADPARENT.UNDEF)
-INF.BADPARENT -> CRITICAL: Message 24 (via logrecv.tcp.INF.BADPARENT)
-INF -> INFO: Finish up, it's closing time. Messages should bear numbers 0 through 24. (via logrecv.tcp.INF)
-<BLANKLINE>
-"""
-import select
-import os, sys, string, struct, cPickle, cStringIO
-import socket, threading
-import logging, logging.handlers, logging.config, test.test_support
+    # config1 adds a little to the standard configuration.
+    config1 = """
+    [loggers]
+    keys=root,parser
+
+    [handlers]
+    keys=hand1
+
+    [formatters]
+    keys=form1
+
+    [logger_root]
+    level=WARNING
+    handlers=
+
+    [logger_parser]
+    level=DEBUG
+    handlers=hand1
+    propagate=1
+    qualname=compiler.parser
+
+    [handler_hand1]
+    class=StreamHandler
+    level=NOTSET
+    formatter=form1
+    args=(sys.stdout,)
+
+    [formatter_form1]
+    format=%(levelname)s ++ %(message)s
+    datefmt=
+    """
 
+    # config2 has a subtle configuration error that should be reported
+    config2 = config1.replace("sys.stdout", "sys.stbout")
 
-BANNER = "-- %-10s %-6s ---------------------------------------------------\n"
+    # config3 has a less subtle configuration error
+    config3 = config1.replace("formatter=form1", "formatter=misspelled_name")
 
-FINISH_UP = "Finish up, it's closing time. Messages should bear numbers 0 through 24."
-#----------------------------------------------------------------------------
-# Test 0
-#----------------------------------------------------------------------------
+    # config4 specifies a custom formatter class to be loaded
+    config4 = """
+    [loggers]
+    keys=root
+
+    [handlers]
+    keys=hand1
+
+    [formatters]
+    keys=form1
+
+    [logger_root]
+    level=NOTSET
+    handlers=hand1
+
+    [handler_hand1]
+    class=StreamHandler
+    level=NOTSET
+    formatter=form1
+    args=(sys.stdout,)
+
+    [formatter_form1]
+    class=""" + __name__ + """.ExceptionFormatter
+    format=%(levelname)s:%(name)s:%(message)s
+    datefmt=
+    """
 
-msgcount = 0
+    def apply_config(self, conf):
+        try:
+            fn = tempfile.mktemp(".ini")
+            f = open(fn, "w")
+            f.write(textwrap.dedent(conf))
+            f.close()
+            logging.config.fileConfig(fn)
+        finally:
+            os.remove(fn)
 
-def nextmessage():
-    global msgcount
-    rv = "Message %d" % msgcount
-    msgcount = msgcount + 1
-    return rv
+    def test_config0_ok(self):
+        # A simple config file which overrides the default settings.
+        with captured_stdout() as output:
+            self.apply_config(self.config0)
+            logger = logging.getLogger()
+            # Won't output anything
+            logger.info(self.next_message())
+            # Outputs a message
+            logger.error(self.next_message())
+            self.assert_log_lines([
+                ('ERROR', '2'),
+            ], stream=output)
+            # Original logger output is empty.
+            self.assert_log_lines([])
+
+    def test_config1_ok(self):
+        # A config file defining a sub-parser as well.
+        with captured_stdout() as output:
+            self.apply_config(self.config1)
+            logger = logging.getLogger("compiler.parser")
+            # Both will output a message
+            logger.info(self.next_message())
+            logger.error(self.next_message())
+            self.assert_log_lines([
+                ('INFO', '1'),
+                ('ERROR', '2'),
+            ], stream=output)
+            # Original logger output is empty.
+            self.assert_log_lines([])
+
+    def test_config2_failure(self):
+        # A simple config file which overrides the default settings.
+        self.assertRaises(StandardError, self.apply_config, self.config2)
+
+    def test_config3_failure(self):
+        # A simple config file which overrides the default settings.
+        self.assertRaises(StandardError, self.apply_config, self.config3)
+
+    def test_config4_ok(self):
+        # A config file specifying a custom formatter class.
+        with captured_stdout() as output:
+            self.apply_config(self.config4)
+            logger = logging.getLogger()
+            try:
+                raise RuntimeError()
+            except RuntimeError:
+                logging.exception("just testing")
+            sys.stdout.seek(0)
+            self.assertEquals(output.getvalue(),
+                "ERROR:root:just testing\nGot a [RuntimeError]\n")
+            # Original logger output is empty
+            self.assert_log_lines([])
 
-#----------------------------------------------------------------------------
-# Log receiver
-#----------------------------------------------------------------------------
 
-TIMEOUT         = 10
+class LogRecordStreamHandler(StreamRequestHandler):
 
-from SocketServer import ThreadingTCPServer, StreamRequestHandler
+    """Handler for a streaming logging request. It saves the log message in the
+    TCP server's 'log_output' attribute."""
 
-class LogRecordStreamHandler(StreamRequestHandler):
-    """
-    Handler for a streaming logging request. It basically logs the record
-    using whatever logging policy is configured locally.
-    """
+    TCP_LOG_END = "!!!END!!!"
 
     def handle(self):
-        """
-        Handle multiple requests - each expected to be a 4-byte length,
+        """Handle multiple requests - each expected to be of 4-byte length,
         followed by the LogRecord in pickle format. Logs the record
-        according to whatever policy is configured locally.
-        """
-        while 1:
-            try:
-                chunk = self.connection.recv(4)
-                if len(chunk) < 4:
-                    break
-                slen = struct.unpack(">L", chunk)[0]
-                chunk = self.connection.recv(slen)
-                while len(chunk) < slen:
-                    chunk = chunk + self.connection.recv(slen - len(chunk))
-                obj = self.unPickle(chunk)
-                record = logging.makeLogRecord(obj)
-                self.handleLogRecord(record)
-            except:
-                raise
+        according to whatever policy is configured locally."""
+        while True:
+            chunk = self.connection.recv(4)
+            if len(chunk) < 4:
+                break
+            slen = struct.unpack(">L", chunk)[0]
+            chunk = self.connection.recv(slen)
+            while len(chunk) < slen:
+                chunk = chunk + self.connection.recv(slen - len(chunk))
+            obj = self.unpickle(chunk)
+            record = logging.makeLogRecord(obj)
+            self.handle_log_record(record)
 
-    def unPickle(self, data):
+    def unpickle(self, data):
         return cPickle.loads(data)
 
-    def handleLogRecord(self, record):
-        logname = "logrecv.tcp." + record.name
-        #If the end-of-messages sentinel is seen, tell the server to terminate
-        if record.msg == FINISH_UP:
+    def handle_log_record(self, record):
+        # If the end-of-messages sentinel is seen, tell the server to
+        #  terminate.
+        if self.TCP_LOG_END in record.msg:
             self.server.abort = 1
-        record.msg = record.msg + " (via " + logname + ")"
-        logger = logging.getLogger("logrecv")
-        logger.handle(record)
-
-# The server sets socketDataProcessed when it's done.
-socketDataProcessed = threading.Event()
-#----------------------------------------------------------------------------
-# Test 5
-#----------------------------------------------------------------------------
-
-test5_config = """
-[loggers]
-keys=root
-
-[handlers]
-keys=hand1
-
-[formatters]
-keys=form1
-
-[logger_root]
-level=NOTSET
-handlers=hand1
-
-[handler_hand1]
-class=StreamHandler
-level=NOTSET
-formatter=form1
-args=(sys.stdout,)
-
-[formatter_form1]
-class=test.test_logging.FriendlyFormatter
-format=%(levelname)s:%(name)s:%(message)s
-datefmt=
-"""
-
-class FriendlyFormatter (logging.Formatter):
-    def formatException(self, ei):
-        return "%s... Don't panic!" % str(ei[0])
-
-
-def test5():
-    loggerDict = logging.getLogger().manager.loggerDict
-    logging._acquireLock()
-    try:
-        saved_handlers = logging._handlers.copy()
-        saved_handler_list = logging._handlerList[:]
-        saved_loggers = loggerDict.copy()
-    finally:
-        logging._releaseLock()
-    try:
-        fn = test.test_support.TESTFN
-        f = open(fn, "w")
-        f.write(test5_config)
-        f.close()
-        logging.config.fileConfig(fn)
-        try:
-            raise KeyError
-        except KeyError:
-            logging.exception("just testing")
-        os.remove(fn)
-        hdlr = logging.getLogger().handlers[0]
-        logging.getLogger().handlers.remove(hdlr)
-    finally:
-        logging._acquireLock()
-        try:
-            logging._handlers.clear()
-            logging._handlers.update(saved_handlers)
-            logging._handlerList[:] = saved_handler_list
-            loggerDict = logging.getLogger().manager.loggerDict
-            loggerDict.clear()
-            loggerDict.update(saved_loggers)
-        finally:
-            logging._releaseLock()
+            return
+        self.server.log_output += record.msg + "\n"
 
 
 class LogRecordSocketReceiver(ThreadingTCPServer):
-    """
-    A simple-minded TCP socket-based logging receiver suitable for test
-    purposes.
-    """
+
+    """A simple-minded TCP socket-based logging receiver suitable for test
+    purposes."""
 
     allow_reuse_address = 1
+    log_output = ""
 
     def __init__(self, host='localhost',
                              port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
                      handler=LogRecordStreamHandler):
         ThreadingTCPServer.__init__(self, (host, port), handler)
         self.abort = False
-        self.timeout = 1
+        self.timeout = 0.1
+        self.finished = threading.Event()
 
     def serve_until_stopped(self):
         while not self.abort:
@@ -2018,217 +704,119 @@
                                        self.timeout)
             if rd:
                 self.handle_request()
-            socketDataProcessed.set()
+        # Notify the main thread that we're about to exit
+        self.finished.set()
         # close the listen socket
         self.server_close()
 
-    def process_request(self, request, client_address):
-        t = threading.Thread(target = self.finish_request,
-                             args = (request, client_address))
-        t.start()
-
-def runTCP(tcpserver):
-    tcpserver.serve_until_stopped()
-
-def banner(nm, typ):
-    sep = BANNER % (nm, typ)
-    sys.stdout.write(sep)
-    sys.stdout.flush()
-
-def test0():
-    ERR = logging.getLogger("ERR")
-    ERR.setLevel(logging.ERROR)
-    INF = logging.getLogger("INF")
-    INF.setLevel(logging.INFO)
-    INF_ERR  = logging.getLogger("INF.ERR")
-    INF_ERR.setLevel(logging.ERROR)
-    DEB = logging.getLogger("DEB")
-    DEB.setLevel(logging.DEBUG)
-
-    INF_UNDEF = logging.getLogger("INF.UNDEF")
-    INF_ERR_UNDEF = logging.getLogger("INF.ERR.UNDEF")
-    UNDEF = logging.getLogger("UNDEF")
-
-    GRANDCHILD = logging.getLogger("INF.BADPARENT.UNDEF")
-    CHILD = logging.getLogger("INF.BADPARENT")
-
-    #These should log
-    ERR.log(logging.FATAL, nextmessage())
-    ERR.error(nextmessage())
-
-    INF.log(logging.FATAL, nextmessage())
-    INF.error(nextmessage())
-    INF.warn(nextmessage())
-    INF.info(nextmessage())
-
-    INF_UNDEF.log(logging.FATAL, nextmessage())
-    INF_UNDEF.error(nextmessage())
-    INF_UNDEF.warn (nextmessage())
-    INF_UNDEF.info (nextmessage())
-
-    INF_ERR.log(logging.FATAL, nextmessage())
-    INF_ERR.error(nextmessage())
-
-    INF_ERR_UNDEF.log(logging.FATAL, nextmessage())
-    INF_ERR_UNDEF.error(nextmessage())
-
-    DEB.log(logging.FATAL, nextmessage())
-    DEB.error(nextmessage())
-    DEB.warn (nextmessage())
-    DEB.info (nextmessage())
-    DEB.debug(nextmessage())
-
-    UNDEF.log(logging.FATAL, nextmessage())
-    UNDEF.error(nextmessage())
-    UNDEF.warn (nextmessage())
-    UNDEF.info (nextmessage())
-
-    GRANDCHILD.log(logging.FATAL, nextmessage())
-    CHILD.log(logging.FATAL, nextmessage())
-
-    #These should not log
-    ERR.warn(nextmessage())
-    ERR.info(nextmessage())
-    ERR.debug(nextmessage())
-
-    INF.debug(nextmessage())
-    INF_UNDEF.debug(nextmessage())
-
-    INF_ERR.warn(nextmessage())
-    INF_ERR.info(nextmessage())
-    INF_ERR.debug(nextmessage())
-    INF_ERR_UNDEF.warn(nextmessage())
-    INF_ERR_UNDEF.info(nextmessage())
-    INF_ERR_UNDEF.debug(nextmessage())
-
-    INF.info(FINISH_UP)
-
-def test_main_inner():
-    rootLogger = logging.getLogger("")
-    rootLogger.setLevel(logging.DEBUG)
-
-    tcpserver = LogRecordSocketReceiver(port=0)
-    port = tcpserver.socket.getsockname()[1]
-
-    # Set up a handler such that all events are sent via a socket to the log
-    # receiver (logrecv).
-    # The handler will only be added to the rootLogger for some of the tests
-    shdlr = logging.handlers.SocketHandler('localhost', port)
-    rootLogger.addHandler(shdlr)
-
-    # Configure the logger for logrecv so events do not propagate beyond it.
-    # The sockLogger output is buffered in memory until the end of the test,
-    # and printed at the end.
-    sockOut = cStringIO.StringIO()
-    sockLogger = logging.getLogger("logrecv")
-    sockLogger.setLevel(logging.DEBUG)
-    sockhdlr = logging.StreamHandler(sockOut)
-    sockhdlr.setFormatter(logging.Formatter(
-                                   "%(name)s -> %(levelname)s: %(message)s"))
-    sockLogger.addHandler(sockhdlr)
-    sockLogger.propagate = 0
-
-    #Set up servers
-    threads = []
-    #sys.stdout.write("About to start TCP server...\n")
-    threads.append(threading.Thread(target=runTCP, args=(tcpserver,)))
-
-    for thread in threads:
-        thread.start()
-    try:
-        test0()
-
-        # XXX(nnorwitz): Try to fix timing related test failures.
-        # This sleep gives us some extra time to read messages.
-        # The test generally only fails on Solaris without this sleep.
-        #time.sleep(2.0)
-        shdlr.close()
-        rootLogger.removeHandler(shdlr)
-
-    finally:
-        #wait for TCP receiver to terminate
-        socketDataProcessed.wait()
-        # ensure the server dies
-        tcpserver.abort = True
-        for thread in threads:
-            thread.join(2.0)
-        print(sockOut.getvalue())
-        sockOut.close()
-        sockLogger.removeHandler(sockhdlr)
-        sockhdlr.close()
-        sys.stdout.flush()
-
-# config0 is a standard configuration.
-config0 = """
-[loggers]
-keys=root
-
-[handlers]
-keys=hand1
-
-[formatters]
-keys=form1
-
-[logger_root]
-level=NOTSET
-handlers=hand1
-
-[handler_hand1]
-class=StreamHandler
-level=NOTSET
-formatter=form1
-args=(sys.stdout,)
-
-[formatter_form1]
-format=%(levelname)s:%(name)s:%(message)s
-datefmt=
-"""
 
-# config1 adds a little to the standard configuration.
-config1 = """
-[loggers]
-keys=root,parser
-
-[handlers]
-keys=hand1
-
-[formatters]
-keys=form1
-
-[logger_root]
-level=NOTSET
-handlers=hand1
-
-[logger_parser]
-level=DEBUG
-handlers=hand1
-propagate=1
-qualname=compiler.parser
-
-[handler_hand1]
-class=StreamHandler
-level=NOTSET
-formatter=form1
-args=(sys.stdout,)
-
-[formatter_form1]
-format=%(levelname)s:%(name)s:%(message)s
-datefmt=
-"""
+class SocketHandlerTest(BaseTest):
 
-def message(s):
-    sys.stdout.write("%s\n" % s)
+    """Test for SocketHandler objects."""
 
-# config2 has a subtle configuration error that should be reported
-config2 = string.replace(config1, "sys.stdout", "sys.stbout")
+    def setUp(self):
+        """Set up a TCP server to receive log messages, and a SocketHandler
+        pointing to that server's address and port."""
+        BaseTest.setUp(self)
+        self.tcpserver = LogRecordSocketReceiver(port=0)
+        self.port = self.tcpserver.socket.getsockname()[1]
+        self.threads = [
+                threading.Thread(target=self.tcpserver.serve_until_stopped)]
+        for thread in self.threads:
+            thread.start()
+
+        self.sock_hdlr = logging.handlers.SocketHandler('localhost', self.port)
+        self.sock_hdlr.setFormatter(self.root_formatter)
+        self.root_logger.removeHandler(self.root_logger.handlers[0])
+        self.root_logger.addHandler(self.sock_hdlr)
 
-# config3 has a less subtle configuration error
-config3 = string.replace(
-    config1, "formatter=form1", "formatter=misspelled_name")
+    def tearDown(self):
+        """Shutdown the TCP server."""
+        try:
+            self.tcpserver.abort = True
+            del self.tcpserver
+            self.root_logger.removeHandler(self.sock_hdlr)
+            self.sock_hdlr.close()
+            for thread in self.threads:
+                thread.join(2.0)
+        finally:
+            BaseTest.tearDown(self)
 
+    def get_output(self):
+        """Get the log output as received by the TCP server."""
+        # Signal the TCP receiver and wait for it to terminate.
+        self.root_logger.critical(LogRecordStreamHandler.TCP_LOG_END)
+        self.tcpserver.finished.wait(2.0)
+        return self.tcpserver.log_output
+
+    def test_output(self):
+        # The log message sent to the SocketHandler is properly received.
+        logger = logging.getLogger("tcp")
+        logger.error("spam")
+        logger.debug("eggs")
+        self.assertEquals(self.get_output(), "spam\neggs\n")
+
+
+class MemoryTest(BaseTest):
+
+    """Test memory persistence of logger objects."""
+
+    def setUp(self):
+        """Create a dict to remember potentially destroyed objects."""
+        BaseTest.setUp(self)
+        self._survivors = {}
+
+    def _watch_for_survival(self, *args):
+        """Watch the given objects for survival, by creating weakrefs to
+        them."""
+        for obj in args:
+            key = id(obj), repr(obj)
+            self._survivors[key] = weakref.ref(obj)
+
+    def _assert_survival(self):
+        """Assert that all objects watched for survival have survived."""
+        # Trigger cycle breaking.
+        gc.collect()
+        dead = []
+        for (id_, repr_), ref in self._survivors.items():
+            if ref() is None:
+                dead.append(repr_)
+        if dead:
+            self.fail("%d objects should have survived "
+                "but have been destroyed: %s" % (len(dead), ", ".join(dead)))
+
+    def test_persistent_loggers(self):
+        # Logger objects are persistent and retain their configuration, even
+        #  if visible references are destroyed.
+        self.root_logger.setLevel(logging.INFO)
+        foo = logging.getLogger("foo")
+        self._watch_for_survival(foo)
+        foo.setLevel(logging.DEBUG)
+        self.root_logger.debug(self.next_message())
+        foo.debug(self.next_message())
+        self.assert_log_lines([
+            ('foo', 'DEBUG', '2'),
+        ])
+        del foo
+        # foo has survived.
+        self._assert_survival()
+        # foo has retained its settings.
+        bar = logging.getLogger("foo")
+        bar.debug(self.next_message())
+        self.assert_log_lines([
+            ('foo', 'DEBUG', '2'),
+            ('foo', 'DEBUG', '3'),
+        ])
+
+
+# Set the locale to the platform-dependent default.  I have no idea
+# why the test does this, but in any case we save the current locale
+# first and restore it at the end.
+ at run_with_locale('LC_ALL', '')
 def test_main():
-    from test import test_support, test_logging
-    test_support.run_doctest(test_logging)
+    run_unittest(BuiltinLevelsTest, BasicFilterTest,
+                    CustomLevelsAndFiltersTest, MemoryHandlerTest,
+                    ConfigFileTest, SocketHandlerTest, MemoryTest)
 
-if __name__=="__main__":
+if __name__ == "__main__":
     test_main()

Modified: python/trunk/Misc/ACKS
==============================================================================
--- python/trunk/Misc/ACKS	(original)
+++ python/trunk/Misc/ACKS	Mon Mar  3 01:38:58 2008
@@ -524,6 +524,7 @@
 François Pinard
 Zach Pincus
 Michael Piotrowski
+Antoine Pitrou
 Michael Pomraning
 Iustin Pop
 John Popplewell

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Mon Mar  3 01:38:58 2008
@@ -1419,7 +1419,7 @@
 Tests
 -----
 
-- Refactor test_logging to use doctest.
+- Refactor test_logging to use unittest.
 
 - Refactor test_profile and test_cprofile to use the same code to profile.
 


More information about the Python-checkins mailing list