mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
sphinx.util.logging supports colorized log
This commit is contained in:
parent
7358512f11
commit
70d6a560f2
@ -15,11 +15,11 @@ import logging.handlers
|
|||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from six import PY2, StringIO, string_types
|
from six import PY2, StringIO
|
||||||
from docutils.utils import get_source_line
|
from docutils.utils import get_source_line
|
||||||
|
|
||||||
from sphinx.errors import SphinxWarning
|
from sphinx.errors import SphinxWarning
|
||||||
from sphinx.util.console import darkred # type: ignore
|
from sphinx.util.console import colorize
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
# For type annotation
|
# For type annotation
|
||||||
@ -30,6 +30,7 @@ if False:
|
|||||||
|
|
||||||
VERBOSE = 15
|
VERBOSE = 15
|
||||||
DEBUG2 = 5
|
DEBUG2 = 5
|
||||||
|
|
||||||
VERBOSITY_MAP = defaultdict(lambda: 0) # type: Dict[int, int]
|
VERBOSITY_MAP = defaultdict(lambda: 0) # type: Dict[int, int]
|
||||||
VERBOSITY_MAP.update({
|
VERBOSITY_MAP.update({
|
||||||
0: logging.INFO,
|
0: logging.INFO,
|
||||||
@ -38,6 +39,13 @@ VERBOSITY_MAP.update({
|
|||||||
3: DEBUG2,
|
3: DEBUG2,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
COLOR_MAP = defaultdict(lambda text: text) # type: Dict[int, unicode]
|
||||||
|
COLOR_MAP.update({
|
||||||
|
logging.WARNING: 'darkred',
|
||||||
|
logging.DEBUG: 'darkgray',
|
||||||
|
DEBUG2: 'lightgray',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def getLogger(name):
|
def getLogger(name):
|
||||||
# type: (str) -> SphinxLoggerAdapter
|
# type: (str) -> SphinxLoggerAdapter
|
||||||
@ -52,16 +60,13 @@ class SphinxWarningLogRecord(logging.LogRecord):
|
|||||||
def getMessage(self):
|
def getMessage(self):
|
||||||
# type: () -> str
|
# type: () -> str
|
||||||
message = super(SphinxWarningLogRecord, self).getMessage()
|
message = super(SphinxWarningLogRecord, self).getMessage()
|
||||||
if isinstance(message, string_types):
|
location = getattr(self, 'location', None)
|
||||||
location = getattr(self, 'location', None)
|
if location:
|
||||||
if location:
|
message = '%s: WARNING: %s' % (location, message)
|
||||||
message = '%s: WARNING: %s' % (location, message)
|
elif 'WARNING:' not in message:
|
||||||
elif 'WARNING:' not in message:
|
message = 'WARNING: %s' % message
|
||||||
message = 'WARNING: %s' % message
|
|
||||||
|
|
||||||
return darkred(message)
|
return message
|
||||||
else:
|
|
||||||
return message
|
|
||||||
|
|
||||||
|
|
||||||
class SphinxLoggerAdapter(logging.LoggerAdapter):
|
class SphinxLoggerAdapter(logging.LoggerAdapter):
|
||||||
@ -103,6 +108,8 @@ class SphinxLoggerAdapter(logging.LoggerAdapter):
|
|||||||
extra['location'] = kwargs.pop('location')
|
extra['location'] = kwargs.pop('location')
|
||||||
if 'nonl' in kwargs:
|
if 'nonl' in kwargs:
|
||||||
extra['nonl'] = kwargs.pop('nonl')
|
extra['nonl'] = kwargs.pop('nonl')
|
||||||
|
if 'color' in kwargs:
|
||||||
|
extra['color'] = kwargs.pop('color')
|
||||||
|
|
||||||
return msg, kwargs
|
return msg, kwargs
|
||||||
|
|
||||||
@ -293,6 +300,19 @@ class WarningLogRecordTranslator(logging.Filter):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ColorizeFormatter(logging.Formatter):
|
||||||
|
def format(self, record):
|
||||||
|
message = super(ColorizeFormatter, self).format(record)
|
||||||
|
color = getattr(record, 'color', None)
|
||||||
|
if color is None:
|
||||||
|
color = COLOR_MAP.get(record.levelno)
|
||||||
|
|
||||||
|
if color:
|
||||||
|
return colorize(color, message)
|
||||||
|
else:
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
def setup(app, status, warning):
|
def setup(app, status, warning):
|
||||||
# type: (Sphinx, IO, IO) -> None
|
# type: (Sphinx, IO, IO) -> None
|
||||||
"""Setup root logger for Sphinx"""
|
"""Setup root logger for Sphinx"""
|
||||||
@ -306,11 +326,13 @@ def setup(app, status, warning):
|
|||||||
info_handler = NewLineStreamHandler(status)
|
info_handler = NewLineStreamHandler(status)
|
||||||
info_handler.addFilter(InfoFilter())
|
info_handler.addFilter(InfoFilter())
|
||||||
info_handler.setLevel(VERBOSITY_MAP.get(app.verbosity))
|
info_handler.setLevel(VERBOSITY_MAP.get(app.verbosity))
|
||||||
|
info_handler.setFormatter(ColorizeFormatter())
|
||||||
|
|
||||||
warning_handler = logging.StreamHandler(warning)
|
warning_handler = logging.StreamHandler(warning)
|
||||||
warning_handler.addFilter(WarningSuppressor(app))
|
warning_handler.addFilter(WarningSuppressor(app))
|
||||||
warning_handler.addFilter(WarningIsErrorFilter(app))
|
warning_handler.addFilter(WarningIsErrorFilter(app))
|
||||||
warning_handler.addFilter(WarningLogRecordTranslator(app))
|
warning_handler.addFilter(WarningLogRecordTranslator(app))
|
||||||
warning_handler.setLevel(logging.WARNING)
|
warning_handler.setLevel(logging.WARNING)
|
||||||
|
warning_handler.setFormatter(ColorizeFormatter())
|
||||||
logger.addHandler(info_handler)
|
logger.addHandler(info_handler)
|
||||||
logger.addHandler(warning_handler)
|
logger.addHandler(warning_handler)
|
||||||
|
@ -14,6 +14,7 @@ from docutils import nodes
|
|||||||
|
|
||||||
from sphinx.errors import SphinxWarning
|
from sphinx.errors import SphinxWarning
|
||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
|
from sphinx.util.console import colorize
|
||||||
from sphinx.util.logging import is_suppressed_warning
|
from sphinx.util.logging import is_suppressed_warning
|
||||||
|
|
||||||
from util import with_app, raises, strip_escseq
|
from util import with_app, raises, strip_escseq
|
||||||
@ -238,3 +239,33 @@ def test_pending_logging(app, status, warning):
|
|||||||
|
|
||||||
# actually logged as ordered
|
# actually logged as ordered
|
||||||
assert 'WARNING: message2\nWARNING: message3' in strip_escseq(warning.getvalue())
|
assert 'WARNING: message2\nWARNING: message3' in strip_escseq(warning.getvalue())
|
||||||
|
|
||||||
|
|
||||||
|
@with_app()
|
||||||
|
def test_colored_logs(app, status, warning):
|
||||||
|
app.verbosity = 3
|
||||||
|
logging.setup(app, status, warning)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# default colors
|
||||||
|
logger.debug2('message1')
|
||||||
|
logger.debug('message2')
|
||||||
|
logger.verbose('message3')
|
||||||
|
logger.info('message4')
|
||||||
|
logger.warning('message5')
|
||||||
|
logger.critical('message6')
|
||||||
|
logger.error('message7')
|
||||||
|
|
||||||
|
assert colorize('lightgray', 'message1') in status.getvalue()
|
||||||
|
assert colorize('darkgray', 'message2') in status.getvalue()
|
||||||
|
assert 'message3\n' in status.getvalue() # not colored
|
||||||
|
assert 'message4\n' in status.getvalue() # not colored
|
||||||
|
assert colorize('darkred', 'WARNING: message5') in warning.getvalue()
|
||||||
|
assert 'WARNING: message6\n' in warning.getvalue() # not colored
|
||||||
|
assert 'WARNING: message7\n' in warning.getvalue() # not colored
|
||||||
|
|
||||||
|
# color specification
|
||||||
|
logger.debug('message8', color='white')
|
||||||
|
logger.info('message9', color='red')
|
||||||
|
assert colorize('white', 'message8') in status.getvalue()
|
||||||
|
assert colorize('red', 'message9') in status.getvalue()
|
||||||
|
Loading…
Reference in New Issue
Block a user