Skip to content

Commit 22005fc

Browse files
committed
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. ........
1 parent 135e990 commit 22005fc

File tree

5 files changed

+107
-24
lines changed

5 files changed

+107
-24
lines changed

Doc/library/logging.rst

+38-17
Original file line numberDiff line numberDiff line change
@@ -244,16 +244,16 @@ With the logger object configured, the following methods create log messages:
244244
methods listed above, but this is how to log at custom log levels.
245245

246246
:func:`getLogger` returns a reference to a logger instance with the specified
247-
if it it is provided, or ``root`` if not. The names are period-separated
247+
if it is provided, or ``root`` if not. The names are period-separated
248248
hierarchical structures. Multiple calls to :func:`getLogger` with the same name
249249
will return a reference to the same logger object. Loggers that are further
250250
down in the hierarchical list are children of loggers higher up in the list.
251251
For example, given a logger with a name of ``foo``, loggers with names of
252-
``foo.bar``, ``foo.bar.baz``, and ``foo.bam`` are all children of ``foo``.
253-
Child loggers propagate messages up to their parent loggers. Because of this,
254-
it is unnecessary to define and configure all the loggers an application uses.
255-
It is sufficient to configure a top-level logger and create child loggers as
256-
needed.
252+
``foo.bar``, ``foo.bar.baz``, and ``foo.bam`` are all descendants of ``foo``.
253+
Child loggers propagate messages up to the handlers associated with their
254+
ancestor loggers. Because of this, it is unnecessary to define and configure
255+
handlers for all the loggers an application uses. It is sufficient to
256+
configure handlers for a top-level logger and create child loggers as needed.
257257

258258

259259
Handlers
@@ -281,15 +281,16 @@ custom handlers) are the following configuration methods:
281281
are there two :func:`setLevel` methods? The level set in the logger
282282
determines which severity of messages it will pass to its handlers. The level
283283
set in each handler determines which messages that handler will send on.
284-
:func:`setFormatter` selects a Formatter object for this handler to use.
284+
285+
* :func:`setFormatter` selects a Formatter object for this handler to use.
285286

286287
* :func:`addFilter` and :func:`removeFilter` respectively configure and
287288
deconfigure filter objects on handlers.
288289

289-
Application code should not directly instantiate and use handlers. Instead, the
290-
:class:`Handler` class is a base class that defines the interface that all
291-
Handlers should have and establishes some default behavior that child classes
292-
can use (or override).
290+
Application code should not directly instantiate and use instances of
291+
:class:`Handler`. Instead, the :class:`Handler` class is a base class that
292+
defines the interface that all handlers should have and establishes some
293+
default behavior that child classes can use (or override).
293294

294295

295296
Formatters
@@ -521,7 +522,9 @@ support desk staff, system administrators, developers). Handlers are passed
521522
can have zero, one or more handlers associated with it (via the
522523
:meth:`addHandler` method of :class:`Logger`). In addition to any handlers
523524
directly associated with a logger, *all handlers associated with all ancestors
524-
of the logger* are called to dispatch the message.
525+
of the logger* are called to dispatch the message (unless the *propagate* flag
526+
for a logger is set to a false value, at which point the passing to ancestor
527+
handlers stops).
525528

526529
Just as for loggers, handlers can have levels associated with them. A handler's
527530
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
849852
.. attribute:: Logger.propagate
850853

851854
If this evaluates to false, logging messages are not passed by this logger or by
852-
child loggers to higher level (ancestor) loggers. The constructor sets this
853-
attribute to 1.
855+
its child loggers to the handlers of higher level (ancestor) loggers. The
856+
constructor sets this attribute to 1.
854857

855858

856859
.. method:: Logger.setLevel(lvl)
@@ -889,6 +892,16 @@ instantiated directly, but always through the module-level function
889892
:const:`NOTSET` is found, and that value is returned.
890893

891894

895+
.. method:: Logger.getChild(suffix)
896+
897+
Returns a logger which is a descendant to this logger, as determined by the suffix.
898+
Thus, ``logging.getLogger('abc').getChild('def.ghi')`` would return the same
899+
logger as would be returned by ``logging.getLogger('abc.def.ghi')``. This is a
900+
convenience method, useful when the parent logger is named using e.g. ``__name__``
901+
rather than a literal string.
902+
903+
.. versionadded:: 3.2
904+
892905
.. method:: Logger.debug(msg, *args, **kwargs)
893906

894907
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.
20122025
or integers - if strings are passed, internal mapping dictionaries are
20132026
used to convert them to integers.
20142027

2015-
**Priorities**
2028+
The symbolic ``LOG_`` values are defined in :class:`SysLogHandler` and
2029+
mirror the values defined in the ``sys/syslog.h`` header file.
20162030

2031+
+------------------------------------------+
2032+
| Priorities |
20172033
+--------------------------+---------------+
20182034
| Name (string) | Symbolic value|
20192035
+==========================+===============+
@@ -2034,8 +2050,8 @@ supports sending logging messages to a remote or local Unix syslog.
20342050
| ``warn`` or ``warning`` | LOG_WARNING |
20352051
+--------------------------+---------------+
20362052

2037-
**Facilities**
2038-
2053+
+-------------------------------+
2054+
| Facilities |
20392055
+---------------+---------------+
20402056
| Name (string) | Symbolic value|
20412057
+===============+===============+
@@ -2481,6 +2497,11 @@ methods of :class:`Logger`, i.e. :meth:`debug`, :meth:`info`, :meth:`warning`,
24812497
methods have the same signatures as their counterparts in :class:`Logger`, so
24822498
you can use the two types of instances interchangeably.
24832499

2500+
.. versionchanged:: 2.7
2501+
2502+
The :meth:`isEnabledFor` method was added to :class:`LoggerAdapter`. This method
2503+
delegates to the underlying logger.
2504+
24842505

24852506
Thread Safety
24862507
-------------

Lib/logging/__init__.py

+36-3
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,18 @@ def __init__(self, name, level, pathname, lineno,
285285
self.threadName = None
286286
if not logMultiprocessing:
287287
self.processName = None
288-
elif 'multiprocessing' not in sys.modules:
289-
self.processName = 'MainProcess'
290288
else:
291-
self.processName = sys.modules['multiprocessing'].current_process().name
289+
self.processName = 'MainProcess'
290+
mp = sys.modules.get('multiprocessing')
291+
if mp is not None:
292+
# Errors may occur if multiprocessing has not finished loading
293+
# yet - e.g. if a custom import hook causes third-party code
294+
# to run when multiprocessing calls import. See issue 8200
295+
# for an example
296+
try:
297+
self.processName = mp.current_process().name
298+
except StandardError:
299+
pass
292300
if logProcesses and hasattr(os, 'getpid'):
293301
self.process = os.getpid()
294302
else:
@@ -1306,6 +1314,25 @@ def isEnabledFor(self, level):
13061314
return 0
13071315
return level >= self.getEffectiveLevel()
13081316

1317+
def getChild(self, suffix):
1318+
"""
1319+
Get a logger which is a descendant to this one.
1320+
1321+
This is a convenience method, such that
1322+
1323+
logging.getLogger('abc').getChild('def.ghi')
1324+
1325+
is the same as
1326+
1327+
logging.getLogger('abc.def.ghi')
1328+
1329+
It's useful, for example, when the parent logger is named using
1330+
__name__ rather than a literal string.
1331+
"""
1332+
if self.root is not self:
1333+
suffix = '.'.join((self.name, suffix))
1334+
return self.manager.getLogger(suffix)
1335+
13091336
class RootLogger(Logger):
13101337
"""
13111338
A root logger is not that different to any other logger, except that
@@ -1410,6 +1437,12 @@ def log(self, level, msg, *args, **kwargs):
14101437
msg, kwargs = self.process(msg, kwargs)
14111438
self.logger.log(level, msg, *args, **kwargs)
14121439

1440+
def isEnabledFor(self, level):
1441+
"""
1442+
See if the underlying logger is enabled for the specified level.
1443+
"""
1444+
return self.logger.isEnabledFor(level)
1445+
14131446
root = RootLogger(WARNING)
14141447
Logger.root = root
14151448
Logger.manager = Manager(Logger.root)

Lib/logging/config.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ def _resolve(name):
9898
def _strip_spaces(alist):
9999
return map(lambda x: x.strip(), alist)
100100

101+
def _encoded(s):
102+
return s if isinstance(s, str) else s.encode('utf-8')
103+
101104
def _create_formatters(cp):
102105
"""Create and return formatters"""
103106
flist = cp.get("formatters", "keys")
@@ -208,7 +211,7 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
208211
#avoid disabling child loggers of explicitly
209212
#named loggers. With a sorted list it is easier
210213
#to find the child loggers.
211-
existing.sort()
214+
existing.sort(key=_encoded)
212215
#We'll keep the list of existing loggers
213216
#which are children of named loggers here...
214217
child_loggers = []
@@ -579,7 +582,7 @@ def configure(self):
579582
#avoid disabling child loggers of explicitly
580583
#named loggers. With a sorted list it is easier
581584
#to find the child loggers.
582-
existing.sort()
585+
existing.sort(key=_encoded)
583586
#We'll keep the list of existing loggers
584587
#which are children of named loggers here...
585588
child_loggers = []

Lib/logging/handlers.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,8 @@ class SysLogHandler(logging.Handler):
633633
LOG_NEWS = 7 # network news subsystem
634634
LOG_UUCP = 8 # UUCP subsystem
635635
LOG_CRON = 9 # clock daemon
636-
LOG_AUTHPRIV = 10 # security/authorization messages (private)
636+
LOG_AUTHPRIV = 10 # security/authorization messages (private)
637+
LOG_FTP = 11 # FTP daemon
637638

638639
# other codes through 15 reserved for system use
639640
LOG_LOCAL0 = 16 # reserved for local use
@@ -665,6 +666,7 @@ class SysLogHandler(logging.Handler):
665666
"authpriv": LOG_AUTHPRIV,
666667
"cron": LOG_CRON,
667668
"daemon": LOG_DAEMON,
669+
"ftp": LOG_FTP,
668670
"kern": LOG_KERN,
669671
"lpr": LOG_LPR,
670672
"mail": LOG_MAIL,

Lib/test/test_logging.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ def setUp(self):
6868
finally:
6969
logging._releaseLock()
7070

71+
# Set two unused loggers: one non-ASCII and one Unicode.
72+
# This is to test correct operation when sorting existing
73+
# loggers in the configuration code. See issue 8201.
74+
logging.getLogger("\xab\xd7\xbb")
75+
logging.getLogger("\u013f\u00d6\u0047")
76+
7177
self.root_logger = logging.getLogger("")
7278
self.original_logging_level = self.root_logger.getEffectiveLevel()
7379

@@ -1731,6 +1737,23 @@ def _log(self, level, msg, args, exc_info=None, extra=None):
17311737
self.assertEqual(logged, ['should appear in logged'])
17321738

17331739

1740+
class ChildLoggerTest(BaseTest):
1741+
def test_child_loggers(self):
1742+
r = logging.getLogger()
1743+
l1 = logging.getLogger('abc')
1744+
l2 = logging.getLogger('def.ghi')
1745+
c1 = r.getChild('xyz')
1746+
c2 = r.getChild('uvw.xyz')
1747+
self.assertTrue(c1 is logging.getLogger('xyz'))
1748+
self.assertTrue(c2 is logging.getLogger('uvw.xyz'))
1749+
c1 = l1.getChild('def')
1750+
c2 = c1.getChild('ghi')
1751+
c3 = l1.getChild('def.ghi')
1752+
self.assertTrue(c1 is logging.getLogger('abc.def'))
1753+
self.assertTrue(c2 is logging.getLogger('abc.def.ghi'))
1754+
self.assertTrue(c2 is c3)
1755+
1756+
17341757
# Set the locale to the platform-dependent default. I have no idea
17351758
# why the test does this, but in any case we save the current locale
17361759
# first and restore it at the end.
@@ -1739,7 +1762,8 @@ def test_main():
17391762
run_unittest(BuiltinLevelsTest, BasicFilterTest,
17401763
CustomLevelsAndFiltersTest, MemoryHandlerTest,
17411764
ConfigFileTest, SocketHandlerTest, MemoryTest,
1742-
EncodingTest, WarningsTest, ConfigDictTest, ManagerTest)
1765+
EncodingTest, WarningsTest, ConfigDictTest, ManagerTest,
1766+
ChildLoggerTest)
17431767

17441768
if __name__ == "__main__":
17451769
test_main()

0 commit comments

Comments
 (0)