logging: Add prefixed_warnings() helper

This commit is contained in:
Takeshi KOMIYA 2018-09-12 20:09:22 +09:00
parent 12e8c7dc93
commit 4ed5c51cff
3 changed files with 84 additions and 1 deletions

View File

@ -62,3 +62,5 @@ Logging API
.. autofunction:: pending_logging() .. autofunction:: pending_logging()
.. autofunction:: pending_warnings() .. autofunction:: pending_warnings()
.. autofunction:: prefixed_warnings()

View File

@ -287,6 +287,53 @@ def skip_warningiserror(skip=True):
handler.removeFilter(disabler) handler.removeFilter(disabler)
@contextmanager
def prefixed_warnings(prefix):
# type: (unicode) -> Generator
"""Prepend prefix to all records for a while.
For example::
>>> with prefixed_warnings("prefix:"):
>>> logger.warning('Warning message!') # => prefix: Warning message!
.. versionadded:: 2.0
"""
logger = logging.getLogger(NAMESPACE)
warning_handler = None
for handler in logger.handlers:
if isinstance(handler, WarningStreamHandler):
warning_handler = handler
break
else:
# warning stream not found
yield
return
prefix_filter = None
for _filter in warning_handler.filters:
if isinstance(_filter, MessagePrefixFilter):
prefix_filter = _filter
break
if prefix_filter:
# already prefixed
try:
previous = prefix_filter.prefix
prefix_filter.prefix = prefix
yield
finally:
prefix_filter.prefix = previous
else:
# not prefixed yet
try:
prefix_filter = MessagePrefixFilter(prefix)
warning_handler.addFilter(prefix_filter)
yield
finally:
warning_handler.removeFilter(prefix_filter)
class LogCollector: class LogCollector:
def __init__(self): def __init__(self):
# type: () -> None # type: () -> None
@ -395,6 +442,21 @@ class DisableWarningIsErrorFilter(logging.Filter):
return True return True
class MessagePrefixFilter(logging.Filter):
"""Prepend prefix to all records."""
def __init__(self, prefix):
# type: (unicode) -> None
self.prefix = prefix
super(MessagePrefixFilter, self).__init__()
def filter(self, record):
# type: (logging.LogRecord) -> bool
if self.prefix:
record.msg = self.prefix + ' ' + record.msg # type: ignore
return True
class SphinxLogRecordTranslator(logging.Filter): class SphinxLogRecordTranslator(logging.Filter):
"""Converts a log record to one Sphinx expects """Converts a log record to one Sphinx expects

View File

@ -20,7 +20,7 @@ from sphinx.errors import SphinxWarning
from sphinx.testing.util import strip_escseq from sphinx.testing.util import strip_escseq
from sphinx.util import logging from sphinx.util import logging
from sphinx.util.console import colorize from sphinx.util.console import colorize
from sphinx.util.logging import is_suppressed_warning from sphinx.util.logging import is_suppressed_warning, prefixed_warnings
from sphinx.util.parallel import ParallelTasks from sphinx.util.parallel import ParallelTasks
@ -330,3 +330,22 @@ def test_skip_warningiserror(app, status, warning):
with logging.pending_warnings(): with logging.pending_warnings():
with logging.skip_warningiserror(False): with logging.skip_warningiserror(False):
logger.warning('message') logger.warning('message')
def test_prefixed_warnings(app, status, warning):
logging.setup(app, status, warning)
logger = logging.getLogger(__name__)
logger.warning('message1')
with prefixed_warnings('PREFIX:'):
logger.warning('message2')
with prefixed_warnings('Another PREFIX:'):
logger.warning('message3')
logger.warning('message4')
logger.warning('message5')
assert 'WARNING: message1' in warning.getvalue()
assert 'WARNING: PREFIX: message2' in warning.getvalue()
assert 'WARNING: Another PREFIX: message3' in warning.getvalue()
assert 'WARNING: PREFIX: message4' in warning.getvalue()
assert 'WARNING: message5' in warning.getvalue()