Commit 9451a1c6 authored by Benjamin Peterson's avatar Benjamin Peterson

Merged revisions...

Merged revisions 77967,77969,77973,77979,77985-77986,78009,78029,78031-78033,78081,78085,78103,78105-78106,78108,78246,78703,78728,78731,78853,78855 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r77967 | vinay.sajip | 2010-02-04 12:48:53 -0600 (Thu, 04 Feb 2010) | 1 line

  Logging: Implemented PEP 391.
........
  r77969 | vinay.sajip | 2010-02-04 14:18:28 -0600 (Thu, 04 Feb 2010) | 1 line

  Removed spurious print statement.
........
  r77973 | vinay.sajip | 2010-02-04 14:23:45 -0600 (Thu, 04 Feb 2010) | 1 line

  Issue #7851: logging: clarification on logging configuration files.
........
  r77979 | vinay.sajip | 2010-02-04 15:40:56 -0600 (Thu, 04 Feb 2010) | 1 line

  Added unit test for cfg:// resolution.
........
  r77985 | vinay.sajip | 2010-02-05 08:52:05 -0600 (Fri, 05 Feb 2010) | 1 line

  Issue #7857: test_logging: listener test now uses find_unused_port().
........
  r77986 | vinay.sajip | 2010-02-05 09:40:20 -0600 (Fri, 05 Feb 2010) | 1 line

  Issue #7857: test_logging: listener tests disabled for now.
........
  r78009 | vinay.sajip | 2010-02-05 17:43:11 -0600 (Fri, 05 Feb 2010) | 1 line

  test_logging: minor tweaks to timeouts, listening tests marked as skipped.
........
  r78029 | vinay.sajip | 2010-02-06 14:00:43 -0600 (Sat, 06 Feb 2010) | 1 line

  Issue #7857: Tentatively re-enabling one test to see effect on buildbots.
........
  r78031 | vinay.sajip | 2010-02-06 14:28:36 -0600 (Sat, 06 Feb 2010) | 1 line

  Issue #7857: Gave server thread more time to get ready, and re-enabled a skipped test.
........
  r78032 | georg.brandl | 2010-02-06 15:54:40 -0600 (Sat, 06 Feb 2010) | 1 line

  Remove unused imports from test_logging.
........
  r78033 | benjamin.peterson | 2010-02-06 16:08:15 -0600 (Sat, 06 Feb 2010) | 1 line

  make waiting for the server to start robust
........
  r78081 | vinay.sajip | 2010-02-07 06:56:54 -0600 (Sun, 07 Feb 2010) | 1 line

  Issue #7869: logging: improved format-time diagnostics and removed some 1.5.2 support code.
........
  r78085 | vinay.sajip | 2010-02-07 07:06:51 -0600 (Sun, 07 Feb 2010) | 1 line

  logging: Removed some more 1.5.2 support code.
........
  r78103 | vinay.sajip | 2010-02-08 00:50:14 -0600 (Mon, 08 Feb 2010) | 1 line

  Removed spurious print statement in test.
........
  r78105 | vinay.sajip | 2010-02-08 09:32:08 -0600 (Mon, 08 Feb 2010) | 1 line

  logging: skipped listening tests because they're not working reliably.
........
  r78106 | vinay.sajip | 2010-02-08 10:05:50 -0600 (Mon, 08 Feb 2010) | 1 line

  Issue #7857: Another attempt to keep the buildbots happy.
........
  r78108 | vinay.sajip | 2010-02-08 15:18:15 -0600 (Mon, 08 Feb 2010) | 1 line

  logging: gingerly re-enabling skipped tests after improving thread sync code in configurator.
........
  r78246 | vinay.sajip | 2010-02-19 17:53:17 -0600 (Fri, 19 Feb 2010) | 1 line

  logging: Documented warnings module integration.
........
  r78703 | vinay.sajip | 2010-03-05 16:11:24 -0600 (Fri, 05 Mar 2010) | 1 line

  Factored out time usage determination into a method, to facilitate alternative formatting implementations in the future.
........
  r78728 | vinay.sajip | 2010-03-06 09:12:08 -0600 (Sat, 06 Mar 2010) | 1 line

  Added schema version test in dictConfig.
........
  r78731 | vinay.sajip | 2010-03-06 09:56:03 -0600 (Sat, 06 Mar 2010) | 1 line

  Added checks for tuples in dictConfig.
........
  r78853 | vinay.sajip | 2010-03-12 00:01:21 -0600 (Fri, 12 Mar 2010) | 1 line

  Issue #8117: logging: Improved algorithm for computing initial rollover time.
........
  r78855 | vinay.sajip | 2010-03-12 03:16:10 -0600 (Fri, 12 Mar 2010) | 1 line

  Issue #8117: Updated NEWS entry and added to logging documentation.
........
parent 7ad96a5a
...@@ -420,6 +420,13 @@ You can see that the config file approach has a few advantages over the Python ...@@ -420,6 +420,13 @@ You can see that the config file approach has a few advantages over the Python
code approach, mainly separation of configuration and code and the ability of code approach, mainly separation of configuration and code and the ability of
noncoders to easily modify the logging properties. noncoders to easily modify the logging properties.
Note that the class names referenced in config files need to be either relative
to the logging module, or absolute values which can be resolved using normal
import mechanisms. Thus, you could use either `handlers.WatchedFileHandler`
(relative to the logging module) or `mypackage.mymodule.MyHandler` (for a
class defined in package `mypackage` and module `mymodule`, where `mypackage`
is available on the Python import path).
.. _library-config: .. _library-config:
Configuring Logging for a Library Configuring Logging for a Library
...@@ -1849,6 +1856,11 @@ timed intervals. ...@@ -1849,6 +1856,11 @@ timed intervals.
The extensions are date-and-time based, using the strftime format The extensions are date-and-time based, using the strftime format
``%Y-%m-%d_%H-%M-%S`` or a leading portion thereof, depending on the ``%Y-%m-%d_%H-%M-%S`` or a leading portion thereof, depending on the
rollover interval. rollover interval.
When computing the next rollover time for the first time (when the handler
is created), the last modification time of an existing log file, or else
the current time, is used to compute when the next rotation will occur.
If the *utc* argument is true, times in UTC will be used; otherwise If the *utc* argument is true, times in UTC will be used; otherwise
local time is used. local time is used.
...@@ -2401,6 +2413,28 @@ module, you may not be able to use logging from within such handlers. This is ...@@ -2401,6 +2413,28 @@ module, you may not be able to use logging from within such handlers. This is
because lock implementations in the :mod:`threading` module are not always because lock implementations in the :mod:`threading` module are not always
re-entrant, and so cannot be invoked from such signal handlers. re-entrant, and so cannot be invoked from such signal handlers.
Integration with the warnings module
------------------------------------
The :func:`captureWarnings` function can be used to integrate :mod:`logging`
with the :mod:`warnings` module.
.. function:: captureWarnings(capture)
This function is used to turn the capture of warnings by logging on and
off.
If `capture` is `True`, warnings issued by the :mod:`warnings` module
will be redirected to the logging system. Specifically, a warning will be
formatted using :func:`warnings.formatwarning` and the resulting string
logged to a logger named "py.warnings" with a severity of `WARNING`.
If `capture` is `False`, the redirection of warnings to the logging system
will stop, and warnings will be redirected to their original destinations
(i.e. those in effect before `captureWarnings(True)` was called).
Configuration Configuration
------------- -------------
......
...@@ -432,6 +432,12 @@ class Formatter(object): ...@@ -432,6 +432,12 @@ class Formatter(object):
s = s[:-1] s = s[:-1]
return s return s
def usesTime(self):
"""
Check if the format uses the creation time of the record.
"""
return self._fmt.find("%(asctime)") >= 0
def format(self, record): def format(self, record):
""" """
Format the specified record as text. Format the specified record as text.
...@@ -440,13 +446,13 @@ class Formatter(object): ...@@ -440,13 +446,13 @@ class Formatter(object):
string formatting operation which yields the returned string. string formatting operation which yields the returned string.
Before formatting the dictionary, a couple of preparatory steps Before formatting the dictionary, a couple of preparatory steps
are carried out. The message attribute of the record is computed are carried out. The message attribute of the record is computed
using LogRecord.getMessage(). If the formatting string contains using LogRecord.getMessage(). If the formatting string uses the
"%(asctime)", formatTime() is called to format the event time. time (as determined by a call to usesTime(), formatTime() is
If there is exception information, it is formatted using called to format the event time. If there is exception information,
formatException() and appended to the message. it is formatted using formatException() and appended to the message.
""" """
record.message = record.getMessage() record.message = record.getMessage()
if self._fmt.find("%(asctime)") >= 0: if self.usesTime():
record.asctime = self.formatTime(record, self.datefmt) record.asctime = self.formatTime(record, self.datefmt)
s = self._fmt % record.__dict__ s = self._fmt % record.__dict__
if record.exc_info: if record.exc_info:
......
...@@ -261,7 +261,6 @@ def _install_loggers(cp, handlers, disable_existing_loggers): ...@@ -261,7 +261,6 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
logger.disabled = 1 logger.disabled = 1
IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I) IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I)
...@@ -448,7 +447,7 @@ class BaseConfigurator(object): ...@@ -448,7 +447,7 @@ class BaseConfigurator(object):
isinstance(value, tuple): isinstance(value, tuple):
value = ConvertingTuple(value) value = ConvertingTuple(value)
value.configurator = self value.configurator = self
elif isinstance(value, str): elif isinstance(value, str): # str for py3k
m = self.CONVERT_PATTERN.match(value) m = self.CONVERT_PATTERN.match(value)
if m: if m:
d = m.groupdict() d = m.groupdict()
...@@ -474,6 +473,12 @@ class BaseConfigurator(object): ...@@ -474,6 +473,12 @@ class BaseConfigurator(object):
setattr(result, name, value) setattr(result, name, value)
return result return result
def as_tuple(self, value):
"""Utility function which converts lists to tuples."""
if isinstance(value, list):
value = tuple(value)
return value
class DictConfigurator(BaseConfigurator): class DictConfigurator(BaseConfigurator):
""" """
Configure logging using a dictionary-like object to describe the Configure logging using a dictionary-like object to describe the
...@@ -484,6 +489,10 @@ class DictConfigurator(BaseConfigurator): ...@@ -484,6 +489,10 @@ class DictConfigurator(BaseConfigurator):
"""Do the configuration.""" """Do the configuration."""
config = self.config config = self.config
if 'version' not in config:
raise ValueError("dictionary doesn't specify a version")
if config['version'] != 1:
raise ValueError("Unsupported version: %s" % config['version'])
incremental = config.pop('incremental', False) incremental = config.pop('incremental', False)
EMPTY_DICT = {} EMPTY_DICT = {}
logging._acquireLock() logging._acquireLock()
...@@ -684,6 +693,12 @@ class DictConfigurator(BaseConfigurator): ...@@ -684,6 +693,12 @@ class DictConfigurator(BaseConfigurator):
except Exception as e: except Exception as e:
raise ValueError('Unable to set target handler ' raise ValueError('Unable to set target handler '
'%r: %s' % (config['target'], e)) '%r: %s' % (config['target'], e))
elif issubclass(klass, logging.handlers.SMTPHandler) and\
'mailhost' in config:
config['mailhost'] = self.as_tuple(config['mailhost'])
elif issubclass(klass, logging.handlers.SysLogHandler) and\
'address' in config:
config['address'] = self.as_tuple(config['address'])
factory = klass factory = klass
kwargs = dict([(k, config[k]) for k in config if valid_ident(k)]) kwargs = dict([(k, config[k]) for k in config if valid_ident(k)])
try: try:
...@@ -788,7 +803,7 @@ def listen(port=DEFAULT_LOGGING_CONFIG_PORT): ...@@ -788,7 +803,7 @@ def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
chunk = self.connection.recv(slen) chunk = self.connection.recv(slen)
while len(chunk) < slen: while len(chunk) < slen:
chunk = chunk + conn.recv(slen - len(chunk)) chunk = chunk + conn.recv(slen - len(chunk))
chunk = chunk.decode('utf-8') chunk = chunk.decode("utf-8")
try: try:
import json import json
d =json.loads(chunk) d =json.loads(chunk)
......
...@@ -25,7 +25,7 @@ To use, simply 'import logging.handlers' and log away! ...@@ -25,7 +25,7 @@ To use, simply 'import logging.handlers' and log away!
""" """
import logging, socket, os, pickle, struct, time, re import logging, socket, os, pickle, struct, time, re
from stat import ST_DEV, ST_INO from stat import ST_DEV, ST_INO, ST_MTIME
try: try:
import codecs import codecs
...@@ -203,7 +203,11 @@ class TimedRotatingFileHandler(BaseRotatingHandler): ...@@ -203,7 +203,11 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
self.extMatch = re.compile(self.extMatch, re.ASCII) self.extMatch = re.compile(self.extMatch, re.ASCII)
self.interval = self.interval * interval # multiply by units requested self.interval = self.interval * interval # multiply by units requested
self.rolloverAt = self.computeRollover(int(time.time())) if os.path.exists(filename):
t = os.stat(filename)[ST_MTIME]
else:
t = int(time.time())
self.rolloverAt = self.computeRollover(t)
def computeRollover(self, currentTime): def computeRollover(self, currentTime):
""" """
......
#!/usr/bin/env python3 #!/usr/bin/env python
# #
# Copyright 2001-2010 by Vinay Sajip. All Rights Reserved. # Copyright 2001-2010 by Vinay Sajip. All Rights Reserved.
# #
...@@ -26,7 +26,6 @@ import logging.handlers ...@@ -26,7 +26,6 @@ import logging.handlers
import logging.config import logging.config
import codecs import codecs
import copy
import pickle import pickle
import io import io
import gc import gc
...@@ -36,7 +35,6 @@ import re ...@@ -36,7 +35,6 @@ import re
import select import select
import socket import socket
from socketserver import ThreadingTCPServer, StreamRequestHandler from socketserver import ThreadingTCPServer, StreamRequestHandler
import string
import struct import struct
import sys import sys
import tempfile import tempfile
...@@ -44,8 +42,6 @@ from test.support import captured_stdout, run_with_locale, run_unittest,\ ...@@ -44,8 +42,6 @@ from test.support import captured_stdout, run_with_locale, run_unittest,\
find_unused_port find_unused_port
import textwrap import textwrap
import threading import threading
import time
import types
import unittest import unittest
import warnings import warnings
import weakref import weakref
...@@ -361,7 +357,7 @@ class CustomLevelsAndFiltersTest(BaseTest): ...@@ -361,7 +357,7 @@ class CustomLevelsAndFiltersTest(BaseTest):
def setUp(self): def setUp(self):
BaseTest.setUp(self) BaseTest.setUp(self)
for k, v in list(my_logging_levels.items()): for k, v in my_logging_levels.items():
logging.addLevelName(k, v) logging.addLevelName(k, v)
def log_at_all_levels(self, logger): def log_at_all_levels(self, logger):
...@@ -831,7 +827,7 @@ class MemoryTest(BaseTest): ...@@ -831,7 +827,7 @@ class MemoryTest(BaseTest):
# Trigger cycle breaking. # Trigger cycle breaking.
gc.collect() gc.collect()
dead = [] dead = []
for (id_, repr_), ref in list(self._survivors.items()): for (id_, repr_), ref in self._survivors.items():
if ref() is None: if ref() is None:
dead.append(repr_) dead.append(repr_)
if dead: if dead:
...@@ -870,7 +866,7 @@ class EncodingTest(BaseTest): ...@@ -870,7 +866,7 @@ class EncodingTest(BaseTest):
# the non-ascii data we write to the log. # the non-ascii data we write to the log.
data = "foo\x80" data = "foo\x80"
try: try:
handler = logging.FileHandler(fn, encoding="utf8") handler = logging.FileHandler(fn, encoding="utf-8")
log.addHandler(handler) log.addHandler(handler)
try: try:
# write non-ascii data to the log. # write non-ascii data to the log.
...@@ -879,7 +875,7 @@ class EncodingTest(BaseTest): ...@@ -879,7 +875,7 @@ class EncodingTest(BaseTest):
log.removeHandler(handler) log.removeHandler(handler)
handler.close() handler.close()
# check we wrote exactly those bytes, ignoring trailing \n etc # check we wrote exactly those bytes, ignoring trailing \n etc
f = open(fn, encoding="utf8") f = open(fn, encoding="utf-8")
try: try:
self.assertEqual(f.read().rstrip(), data) self.assertEqual(f.read().rstrip(), data)
finally: finally:
...@@ -956,6 +952,7 @@ class ConfigDictTest(BaseTest): ...@@ -956,6 +952,7 @@ class ConfigDictTest(BaseTest):
# config0 is a standard configuration. # config0 is a standard configuration.
config0 = { config0 = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -977,6 +974,7 @@ class ConfigDictTest(BaseTest): ...@@ -977,6 +974,7 @@ class ConfigDictTest(BaseTest):
# config1 adds a little to the standard configuration. # config1 adds a little to the standard configuration.
config1 = { config1 = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1003,6 +1001,7 @@ class ConfigDictTest(BaseTest): ...@@ -1003,6 +1001,7 @@ class ConfigDictTest(BaseTest):
# config2 has a subtle configuration error that should be reported # config2 has a subtle configuration error that should be reported
config2 = { config2 = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1029,6 +1028,7 @@ class ConfigDictTest(BaseTest): ...@@ -1029,6 +1028,7 @@ class ConfigDictTest(BaseTest):
#As config1 but with a misspelt level on a handler #As config1 but with a misspelt level on a handler
config2a = { config2a = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1056,6 +1056,7 @@ class ConfigDictTest(BaseTest): ...@@ -1056,6 +1056,7 @@ class ConfigDictTest(BaseTest):
#As config1 but with a misspelt level on a logger #As config1 but with a misspelt level on a logger
config2b = { config2b = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1082,6 +1083,7 @@ class ConfigDictTest(BaseTest): ...@@ -1082,6 +1083,7 @@ class ConfigDictTest(BaseTest):
# config3 has a less subtle configuration error # config3 has a less subtle configuration error
config3 = { config3 = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1108,6 +1110,7 @@ class ConfigDictTest(BaseTest): ...@@ -1108,6 +1110,7 @@ class ConfigDictTest(BaseTest):
# config4 specifies a custom formatter class to be loaded # config4 specifies a custom formatter class to be loaded
config4 = { config4 = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'()' : __name__ + '.ExceptionFormatter', '()' : __name__ + '.ExceptionFormatter',
...@@ -1130,6 +1133,7 @@ class ConfigDictTest(BaseTest): ...@@ -1130,6 +1133,7 @@ class ConfigDictTest(BaseTest):
# As config4 but using an actual callable rather than a string # As config4 but using an actual callable rather than a string
config4a = { config4a = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'()' : ExceptionFormatter, '()' : ExceptionFormatter,
...@@ -1163,6 +1167,7 @@ class ConfigDictTest(BaseTest): ...@@ -1163,6 +1167,7 @@ class ConfigDictTest(BaseTest):
# config5 specifies a custom handler class to be loaded # config5 specifies a custom handler class to be loaded
config5 = { config5 = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1190,6 +1195,7 @@ class ConfigDictTest(BaseTest): ...@@ -1190,6 +1195,7 @@ class ConfigDictTest(BaseTest):
# config6 specifies a custom handler class to be loaded # config6 specifies a custom handler class to be loaded
# but has bad arguments # but has bad arguments
config6 = { config6 = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1218,6 +1224,7 @@ class ConfigDictTest(BaseTest): ...@@ -1218,6 +1224,7 @@ class ConfigDictTest(BaseTest):
#config 7 does not define compiler.parser but defines compiler.lexer #config 7 does not define compiler.parser but defines compiler.lexer
#so compiler.parser should be disabled after applying it #so compiler.parser should be disabled after applying it
config7 = { config7 = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1243,6 +1250,7 @@ class ConfigDictTest(BaseTest): ...@@ -1243,6 +1250,7 @@ class ConfigDictTest(BaseTest):
} }
config8 = { config8 = {
'version': 1,
'disable_existing_loggers' : False, 'disable_existing_loggers' : False,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
...@@ -1271,6 +1279,7 @@ class ConfigDictTest(BaseTest): ...@@ -1271,6 +1279,7 @@ class ConfigDictTest(BaseTest):
} }
config9 = { config9 = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1296,6 +1305,7 @@ class ConfigDictTest(BaseTest): ...@@ -1296,6 +1305,7 @@ class ConfigDictTest(BaseTest):
} }
config9a = { config9a = {
'version': 1,
'incremental' : True, 'incremental' : True,
'handlers' : { 'handlers' : {
'hand1' : { 'hand1' : {
...@@ -1310,6 +1320,7 @@ class ConfigDictTest(BaseTest): ...@@ -1310,6 +1320,7 @@ class ConfigDictTest(BaseTest):
} }
config9b = { config9b = {
'version': 1,
'incremental' : True, 'incremental' : True,
'handlers' : { 'handlers' : {
'hand1' : { 'hand1' : {
...@@ -1325,6 +1336,7 @@ class ConfigDictTest(BaseTest): ...@@ -1325,6 +1336,7 @@ class ConfigDictTest(BaseTest):
#As config1 but with a filter added #As config1 but with a filter added
config10 = { config10 = {
'version': 1,
'formatters': { 'formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1358,6 +1370,68 @@ class ConfigDictTest(BaseTest): ...@@ -1358,6 +1370,68 @@ class ConfigDictTest(BaseTest):
#As config1 but using cfg:// references #As config1 but using cfg:// references
config11 = { config11 = {
'version': 1,
'true_formatters': {
'form1' : {
'format' : '%(levelname)s ++ %(message)s',
},
},
'handler_configs': {
'hand1' : {
'class' : 'logging.StreamHandler',
'formatter' : 'form1',
'level' : 'NOTSET',
'stream' : 'ext://sys.stdout',
},
},
'formatters' : 'cfg://true_formatters',
'handlers' : {
'hand1' : 'cfg://handler_configs[hand1]',
},
'loggers' : {
'compiler.parser' : {
'level' : 'DEBUG',
'handlers' : ['hand1'],
},
},
'root' : {
'level' : 'WARNING',
},
}
#As config11 but missing the version key
config12 = {
'true_formatters': {
'form1' : {
'format' : '%(levelname)s ++ %(message)s',
},
},
'handler_configs': {
'hand1' : {
'class' : 'logging.StreamHandler',
'formatter' : 'form1',
'level' : 'NOTSET',
'stream' : 'ext://sys.stdout',
},
},
'formatters' : 'cfg://true_formatters',
'handlers' : {
'hand1' : 'cfg://handler_configs[hand1]',
},
'loggers' : {
'compiler.parser' : {
'level' : 'DEBUG',
'handlers' : ['hand1'],
},
},
'root' : {
'level' : 'WARNING',
},
}
#As config11 but using an unsupported version
config13 = {
'version': 2,
'true_formatters': { 'true_formatters': {
'form1' : { 'form1' : {
'format' : '%(levelname)s ++ %(message)s', 'format' : '%(levelname)s ++ %(message)s',
...@@ -1573,13 +1647,19 @@ class ConfigDictTest(BaseTest): ...@@ -1573,13 +1647,19 @@ class ConfigDictTest(BaseTest):
def test_config11_ok(self): def test_config11_ok(self):
self.test_config1_ok(self.config11) self.test_config1_ok(self.config11)
def test_config12_failure(self):
self.assertRaises(Exception, self.apply_config, self.config12)
def test_config13_failure(self):
self.assertRaises(Exception, self.apply_config, self.config13)
def setup_via_listener(self, text): def setup_via_listener(self, text):
text = text.encode("utf-8")
port = find_unused_port() port = find_unused_port()
t = logging.config.listen(port) t = logging.config.listen(port)
t.start() t.start()
t.ready.wait() t.ready.wait()
t.ready.clear() t.ready.clear()
text = text.encode('utf-8')
try: try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2.0) sock.settimeout(2.0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment