Merged revisions 79279,79284,79293,79373,79376,79379,79876,79888 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r79279 | vinay.sajip | 2010-03-22 07:33:08 -0500 (Mon, 22 Mar 2010) | 1 line

  Issue #8200: logging: Handle errors when multiprocessing is not fully loaded when logging occurs.
........
  r79284 | vinay.sajip | 2010-03-22 08:02:28 -0500 (Mon, 22 Mar 2010) | 1 line

  Issue #8201: logging: Handle config errors when non-ASCII and Unicode logger names exist at the same time.
........
  r79293 | vinay.sajip | 2010-03-22 10:29:01 -0500 (Mon, 22 Mar 2010) | 1 line

  logging: Added getChild utility method to Logger and added isEnabledFor method to LoggerAdapter.
........
  r79373 | vinay.sajip | 2010-03-24 09:31:21 -0500 (Wed, 24 Mar 2010) | 1 line

  logging: Added LOG_FTP for SysLogHandler and updated documentation.
........
  r79376 | vinay.sajip | 2010-03-24 10:10:40 -0500 (Wed, 24 Mar 2010) | 1 line

  logging: Documentation tweak.
........
  r79379 | vinay.sajip | 2010-03-24 12:36:35 -0500 (Wed, 24 Mar 2010) | 1 line

  logging: Updated SysLogHandler documentation.
........
  r79876 | vinay.sajip | 2010-04-06 17:32:37 -0500 (Tue, 06 Apr 2010) | 1 line

  Issue #8327: logging: Clarification of propagation functionality in documentation.
........
  r79888 | vinay.sajip | 2010-04-07 04:40:52 -0500 (Wed, 07 Apr 2010) | 1 line

  Issue #8331: logging: fixed some grammatical errors in documentation.
........
This commit is contained in:
Benjamin Peterson 2010-04-11 16:25:06 +00:00
parent 135e990a75
commit 22005fc5ba
5 changed files with 107 additions and 24 deletions

View File

@ -244,16 +244,16 @@ With the logger object configured, the following methods create log messages:
methods listed above, but this is how to log at custom log levels.
:func:`getLogger` returns a reference to a logger instance with the specified
if it it is provided, or ``root`` if not. The names are period-separated
if it is provided, or ``root`` if not. The names are period-separated
hierarchical structures. Multiple calls to :func:`getLogger` with the same name
will return a reference to the same logger object. Loggers that are further
down in the hierarchical list are children of loggers higher up in the list.
For example, given a logger with a name of ``foo``, loggers with names of
``foo.bar``, ``foo.bar.baz``, and ``foo.bam`` are all children of ``foo``.
Child loggers propagate messages up to their parent loggers. Because of this,
it is unnecessary to define and configure all the loggers an application uses.
It is sufficient to configure a top-level logger and create child loggers as
needed.
``foo.bar``, ``foo.bar.baz``, and ``foo.bam`` are all descendants of ``foo``.
Child loggers propagate messages up to the handlers associated with their
ancestor loggers. Because of this, it is unnecessary to define and configure
handlers for all the loggers an application uses. It is sufficient to
configure handlers for a top-level logger and create child loggers as needed.
Handlers
@ -281,15 +281,16 @@ custom handlers) are the following configuration methods:
are there two :func:`setLevel` methods? The level set in the logger
determines which severity of messages it will pass to its handlers. The level
set in each handler determines which messages that handler will send on.
:func:`setFormatter` selects a Formatter object for this handler to use.
* :func:`setFormatter` selects a Formatter object for this handler to use.
* :func:`addFilter` and :func:`removeFilter` respectively configure and
deconfigure filter objects on handlers.
Application code should not directly instantiate and use handlers. Instead, the
:class:`Handler` class is a base class that defines the interface that all
Handlers should have and establishes some default behavior that child classes
can use (or override).
Application code should not directly instantiate and use instances of
:class:`Handler`. Instead, the :class:`Handler` class is a base class that
defines the interface that all handlers should have and establishes some
default behavior that child classes can use (or override).
Formatters
@ -521,7 +522,9 @@ support desk staff, system administrators, developers). Handlers are passed
can have zero, one or more handlers associated with it (via the
:meth:`addHandler` method of :class:`Logger`). In addition to any handlers
directly associated with a logger, *all handlers associated with all ancestors
of the logger* are called to dispatch the message.
of the logger* are called to dispatch the message (unless the *propagate* flag
for a logger is set to a false value, at which point the passing to ancestor
handlers stops).
Just as for loggers, handlers can have levels associated with them. A handler's
level acts as a filter in the same way as a logger's level does. If a handler
@ -849,8 +852,8 @@ instantiated directly, but always through the module-level function
.. attribute:: Logger.propagate
If this evaluates to false, logging messages are not passed by this logger or by
child loggers to higher level (ancestor) loggers. The constructor sets this
attribute to 1.
its child loggers to the handlers of higher level (ancestor) loggers. The
constructor sets this attribute to 1.
.. method:: Logger.setLevel(lvl)
@ -889,6 +892,16 @@ instantiated directly, but always through the module-level function
:const:`NOTSET` is found, and that value is returned.
.. method:: Logger.getChild(suffix)
Returns a logger which is a descendant to this logger, as determined by the suffix.
Thus, ``logging.getLogger('abc').getChild('def.ghi')`` would return the same
logger as would be returned by ``logging.getLogger('abc.def.ghi')``. This is a
convenience method, useful when the parent logger is named using e.g. ``__name__``
rather than a literal string.
.. versionadded:: 3.2
.. method:: Logger.debug(msg, *args, **kwargs)
Logs a message with level :const:`DEBUG` on this logger. The *msg* is the
@ -2012,8 +2025,11 @@ supports sending logging messages to a remote or local Unix syslog.
or integers - if strings are passed, internal mapping dictionaries are
used to convert them to integers.
**Priorities**
The symbolic ``LOG_`` values are defined in :class:`SysLogHandler` and
mirror the values defined in the ``sys/syslog.h`` header file.
+------------------------------------------+
| Priorities |
+--------------------------+---------------+
| Name (string) | Symbolic value|
+==========================+===============+
@ -2034,8 +2050,8 @@ supports sending logging messages to a remote or local Unix syslog.
| ``warn`` or ``warning`` | LOG_WARNING |
+--------------------------+---------------+
**Facilities**
+-------------------------------+
| Facilities |
+---------------+---------------+
| Name (string) | Symbolic value|
+===============+===============+
@ -2481,6 +2497,11 @@ methods of :class:`Logger`, i.e. :meth:`debug`, :meth:`info`, :meth:`warning`,
methods have the same signatures as their counterparts in :class:`Logger`, so
you can use the two types of instances interchangeably.
.. versionchanged:: 2.7
The :meth:`isEnabledFor` method was added to :class:`LoggerAdapter`. This method
delegates to the underlying logger.
Thread Safety
-------------

View File

@ -285,10 +285,18 @@ class LogRecord(object):
self.threadName = None
if not logMultiprocessing:
self.processName = None
elif 'multiprocessing' not in sys.modules:
self.processName = 'MainProcess'
else:
self.processName = sys.modules['multiprocessing'].current_process().name
self.processName = 'MainProcess'
mp = sys.modules.get('multiprocessing')
if mp is not None:
# Errors may occur if multiprocessing has not finished loading
# yet - e.g. if a custom import hook causes third-party code
# to run when multiprocessing calls import. See issue 8200
# for an example
try:
self.processName = mp.current_process().name
except StandardError:
pass
if logProcesses and hasattr(os, 'getpid'):
self.process = os.getpid()
else:
@ -1306,6 +1314,25 @@ class Logger(Filterer):
return 0
return level >= self.getEffectiveLevel()
def getChild(self, suffix):
"""
Get a logger which is a descendant to this one.
This is a convenience method, such that
logging.getLogger('abc').getChild('def.ghi')
is the same as
logging.getLogger('abc.def.ghi')
It's useful, for example, when the parent logger is named using
__name__ rather than a literal string.
"""
if self.root is not self:
suffix = '.'.join((self.name, suffix))
return self.manager.getLogger(suffix)
class RootLogger(Logger):
"""
A root logger is not that different to any other logger, except that
@ -1410,6 +1437,12 @@ class LoggerAdapter(object):
msg, kwargs = self.process(msg, kwargs)
self.logger.log(level, msg, *args, **kwargs)
def isEnabledFor(self, level):
"""
See if the underlying logger is enabled for the specified level.
"""
return self.logger.isEnabledFor(level)
root = RootLogger(WARNING)
Logger.root = root
Logger.manager = Manager(Logger.root)

View File

@ -98,6 +98,9 @@ def _resolve(name):
def _strip_spaces(alist):
return map(lambda x: x.strip(), alist)
def _encoded(s):
return s if isinstance(s, str) else s.encode('utf-8')
def _create_formatters(cp):
"""Create and return formatters"""
flist = cp.get("formatters", "keys")
@ -208,7 +211,7 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
#avoid disabling child loggers of explicitly
#named loggers. With a sorted list it is easier
#to find the child loggers.
existing.sort()
existing.sort(key=_encoded)
#We'll keep the list of existing loggers
#which are children of named loggers here...
child_loggers = []
@ -579,7 +582,7 @@ class DictConfigurator(BaseConfigurator):
#avoid disabling child loggers of explicitly
#named loggers. With a sorted list it is easier
#to find the child loggers.
existing.sort()
existing.sort(key=_encoded)
#We'll keep the list of existing loggers
#which are children of named loggers here...
child_loggers = []

View File

@ -633,7 +633,8 @@ class SysLogHandler(logging.Handler):
LOG_NEWS = 7 # network news subsystem
LOG_UUCP = 8 # UUCP subsystem
LOG_CRON = 9 # clock daemon
LOG_AUTHPRIV = 10 # security/authorization messages (private)
LOG_AUTHPRIV = 10 # security/authorization messages (private)
LOG_FTP = 11 # FTP daemon
# other codes through 15 reserved for system use
LOG_LOCAL0 = 16 # reserved for local use
@ -665,6 +666,7 @@ class SysLogHandler(logging.Handler):
"authpriv": LOG_AUTHPRIV,
"cron": LOG_CRON,
"daemon": LOG_DAEMON,
"ftp": LOG_FTP,
"kern": LOG_KERN,
"lpr": LOG_LPR,
"mail": LOG_MAIL,

View File

@ -68,6 +68,12 @@ class BaseTest(unittest.TestCase):
finally:
logging._releaseLock()
# Set two unused loggers: one non-ASCII and one Unicode.
# This is to test correct operation when sorting existing
# loggers in the configuration code. See issue 8201.
logging.getLogger("\xab\xd7\xbb")
logging.getLogger("\u013f\u00d6\u0047")
self.root_logger = logging.getLogger("")
self.original_logging_level = self.root_logger.getEffectiveLevel()
@ -1731,6 +1737,23 @@ class ManagerTest(BaseTest):
self.assertEqual(logged, ['should appear in logged'])
class ChildLoggerTest(BaseTest):
def test_child_loggers(self):
r = logging.getLogger()
l1 = logging.getLogger('abc')
l2 = logging.getLogger('def.ghi')
c1 = r.getChild('xyz')
c2 = r.getChild('uvw.xyz')
self.assertTrue(c1 is logging.getLogger('xyz'))
self.assertTrue(c2 is logging.getLogger('uvw.xyz'))
c1 = l1.getChild('def')
c2 = c1.getChild('ghi')
c3 = l1.getChild('def.ghi')
self.assertTrue(c1 is logging.getLogger('abc.def'))
self.assertTrue(c2 is logging.getLogger('abc.def.ghi'))
self.assertTrue(c2 is c3)
# 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.
@ -1739,7 +1762,8 @@ def test_main():
run_unittest(BuiltinLevelsTest, BasicFilterTest,
CustomLevelsAndFiltersTest, MemoryHandlerTest,
ConfigFileTest, SocketHandlerTest, MemoryTest,
EncodingTest, WarningsTest, ConfigDictTest, ManagerTest)
EncodingTest, WarningsTest, ConfigDictTest, ManagerTest,
ChildLoggerTest)
if __name__ == "__main__":
test_main()