Merged revisions 68915 via svnmerge from

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

........
  r68915 | jesse.noller | 2009-01-24 21:36:13 -0600 (Sat, 24 Jan 2009) | 1 line

  Properly document multiprocessing's logging support, resolve outstanding issues with the custom levels
........
This commit is contained in:
Jesse Noller 2009-03-31 15:01:45 +00:00
parent 5b19e62b88
commit 8b56d47d01
5 changed files with 82 additions and 20 deletions

View File

@ -1857,30 +1857,74 @@ handler type) for messages from different processes to get mixed up.
Returns the logger used by :mod:`multiprocessing`. If necessary, a new one
will be created.
When first created the logger has level :data:`logging.NOTSET` and has a
handler which sends output to :data:`sys.stderr` using format
``'[%(levelname)s/%(processName)s] %(message)s'``. (The logger allows use of
the non-standard ``'%(processName)s'`` format.) Message sent to this logger
will not by default propagate to the root logger.
When first created the logger has level :data:`logging.NOTSET` and no
default handler. Messages sent to this logger will not by default propagate
to the root logger.
Note that on Windows child processes will only inherit the level of the
parent process's logger -- any other customization of the logger will not be
inherited.
.. currentmodule:: multiprocessing
.. function:: log_to_stderr()
This function performs a call to :func:`get_logger` but in addition to
returning the logger created by get_logger, it adds a handler which sends
output to :data:`sys.stderr` using format
``'[%(levelname)s/%(processName)s] %(message)s'``.
Below is an example session with logging turned on::
>>> import multiprocessing, logging
>>> logger = multiprocessing.get_logger()
>>> logger = multiprocessing.log_to_stderr()
>>> logger.setLevel(logging.INFO)
>>> logger.warning('doomed')
[WARNING/MainProcess] doomed
>>> m = multiprocessing.Manager()
[INFO/SyncManager-1] child process calling self.run()
[INFO/SyncManager-1] manager bound to '\\\\.\\pipe\\pyc-2776-0-lj0tfa'
[INFO/SyncManager-1] created temp directory /.../pymp-Wh47O_
[INFO/SyncManager-1] manager serving at '/.../listener-lWsERs'
>>> del m
[INFO/MainProcess] sending shutdown message to manager
[INFO/SyncManager-1] manager exiting with exitcode 0
In addition to having these two logging functions, the multiprocessing also
exposes two additional logging level attributes. These are :const:`SUBWARNING`
and :const:`SUBDEBUG`. The table below illustrates where theses fit in the
normal level hierarchy.
+----------------+----------------+
| Level | Numeric value |
+================+================+
| ``SUBWARNING`` | 25 |
+----------------+----------------+
| ``SUBDEBUG`` | 5 |
+----------------+----------------+
For a full table of logging levels, see the :mod:`logging` module.
These additional logging levels are used primarily for certain debug messages
within the multiprocessing module. Below is the same example as above, except
with :const:`SUBDEBUG` enabled::
>>> import multiprocessing, logging
>>> logger = multiprocessing.log_to_stderr()
>>> logger.setLevel(multiprocessing.SUBDEBUG)
>>> logger.warning('doomed')
[WARNING/MainProcess] doomed
>>> m = multiprocessing.Manager()
[INFO/SyncManager-1] child process calling self.run()
[INFO/SyncManager-1] created temp directory /.../pymp-djGBXN
[INFO/SyncManager-1] manager serving at '/.../pymp-djGBXN/listener-knBYGe'
>>> del m
[SUBDEBUG/MainProcess] finalizer calling ...
[INFO/MainProcess] sending shutdown message to manager
[DEBUG/SyncManager-1] manager received shutdown message
[SUBDEBUG/SyncManager-1] calling <Finalize object, callback=unlink, ...
[SUBDEBUG/SyncManager-1] finalizer calling <built-in function unlink> ...
[SUBDEBUG/SyncManager-1] calling <Finalize object, dead>
[SUBDEBUG/SyncManager-1] finalizer calling <function rmtree at 0x5aa730> ...
[INFO/SyncManager-1] manager exiting with exitcode 0
The :mod:`multiprocessing.dummy` module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -48,7 +48,7 @@ __all__ = [
'allow_connection_pickling', 'BufferTooShort', 'TimeoutError',
'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Condition',
'Event', 'Queue', 'JoinableQueue', 'Pool', 'Value', 'Array',
'RawValue', 'RawArray'
'RawValue', 'RawArray', 'SUBDEBUG', 'SUBWARNING',
]
__author__ = 'R. Oudkerk (r.m.oudkerk@gmail.com)'
@ -61,6 +61,7 @@ import os
import sys
from multiprocessing.process import Process, current_process, active_children
from multiprocessing.util import SUBDEBUG, SUBWARNING
#
# Exceptions

View File

@ -17,7 +17,8 @@ from multiprocessing.process import current_process, active_children
__all__ = [
'sub_debug', 'debug', 'info', 'sub_warning', 'get_logger',
'log_to_stderr', 'get_temp_dir', 'register_after_fork',
'is_exiting', 'Finalize', 'ForkAwareThreadLock', 'ForkAwareLocal'
'is_exiting', 'Finalize', 'ForkAwareThreadLock', 'ForkAwareLocal',
'SUBDEBUG', 'SUBWARNING',
]
#
@ -57,19 +58,27 @@ def get_logger():
Returns logger used by multiprocessing
'''
global _logger
import logging, atexit
if not _logger:
import logging, atexit
logging._acquireLock()
try:
if not _logger:
# XXX multiprocessing should cleanup before logging
if hasattr(atexit, 'unregister'):
atexit.unregister(_exit_function)
atexit.register(_exit_function)
else:
atexit._exithandlers.remove((_exit_function, (), {}))
atexit._exithandlers.append((_exit_function, (), {}))
_logger = logging.getLogger(LOGGER_NAME)
_logger.propagate = 0
logging.addLevelName(SUBDEBUG, 'SUBDEBUG')
logging.addLevelName(SUBWARNING, 'SUBWARNING')
_logger = logging.getLogger(LOGGER_NAME)
# XXX multiprocessing should cleanup before logging
if hasattr(atexit, 'unregister'):
atexit.unregister(_exit_function)
atexit.register(_exit_function)
else:
atexit._exithandlers.remove((_exit_function, (), {}))
atexit._exithandlers.append((_exit_function, (), {}))
finally:
logging._releaseLock()
return _logger
@ -79,14 +88,17 @@ def log_to_stderr(level=None):
'''
global _log_to_stderr
import logging
logger = get_logger()
formatter = logging.Formatter(DEFAULT_LOGGING_FORMAT)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
if level is not None:
if level:
logger.setLevel(level)
_log_to_stderr = True
return _logger
#
# Function returning a temp directory which will be removed on exit

View File

@ -778,3 +778,4 @@ Siebren van der Zee
Uwe Zessin
Tarek ZiadŽ
Peter Åstrand
Jesse Noller

View File

@ -92,6 +92,10 @@ Core and Builtins
Library
-------
- Fix and properly document the multiprocessing module's logging
support, expose the internal levels and provide proper usage
examples.
- Issue #5387: Fixed mmap.move crash by integer overflow.
- Issue #5261: Patch multiprocessing's semaphore.c to support context