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:
parent
135e990a75
commit
22005fc5ba
|
@ -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
|
||||
-------------
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue