summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sphinx/util/logging.py46
-rw-r--r--tests/test_util_logging.py31
2 files changed, 65 insertions, 12 deletions
diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py
index 9ebd661a4..10043ccd4 100644
--- a/sphinx/util/logging.py
+++ b/sphinx/util/logging.py
@@ -15,11 +15,11 @@ import logging.handlers
from contextlib import contextmanager
from collections import defaultdict
-from six import PY2, StringIO, string_types
+from six import PY2, StringIO
from docutils.utils import get_source_line
from sphinx.errors import SphinxWarning
-from sphinx.util.console import darkred # type: ignore
+from sphinx.util.console import colorize
if False:
# For type annotation
@@ -30,6 +30,7 @@ if False:
VERBOSE = 15
DEBUG2 = 5
+
VERBOSITY_MAP = defaultdict(lambda: 0) # type: Dict[int, int]
VERBOSITY_MAP.update({
0: logging.INFO,
@@ -38,6 +39,13 @@ VERBOSITY_MAP.update({
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):
# type: (str) -> SphinxLoggerAdapter
@@ -52,16 +60,13 @@ class SphinxWarningLogRecord(logging.LogRecord):
def getMessage(self):
# type: () -> str
message = super(SphinxWarningLogRecord, self).getMessage()
- if isinstance(message, string_types):
- location = getattr(self, 'location', None)
- if location:
- message = '%s: WARNING: %s' % (location, message)
- elif 'WARNING:' not in message:
- message = 'WARNING: %s' % message
-
- return darkred(message)
- else:
- return message
+ location = getattr(self, 'location', None)
+ if location:
+ message = '%s: WARNING: %s' % (location, message)
+ elif 'WARNING:' not in message:
+ message = 'WARNING: %s' % message
+
+ return message
class SphinxLoggerAdapter(logging.LoggerAdapter):
@@ -103,6 +108,8 @@ class SphinxLoggerAdapter(logging.LoggerAdapter):
extra['location'] = kwargs.pop('location')
if 'nonl' in kwargs:
extra['nonl'] = kwargs.pop('nonl')
+ if 'color' in kwargs:
+ extra['color'] = kwargs.pop('color')
return msg, kwargs
@@ -293,6 +300,19 @@ class WarningLogRecordTranslator(logging.Filter):
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):
# type: (Sphinx, IO, IO) -> None
"""Setup root logger for Sphinx"""
@@ -306,11 +326,13 @@ def setup(app, status, warning):
info_handler = NewLineStreamHandler(status)
info_handler.addFilter(InfoFilter())
info_handler.setLevel(VERBOSITY_MAP.get(app.verbosity))
+ info_handler.setFormatter(ColorizeFormatter())
warning_handler = logging.StreamHandler(warning)
warning_handler.addFilter(WarningSuppressor(app))
warning_handler.addFilter(WarningIsErrorFilter(app))
warning_handler.addFilter(WarningLogRecordTranslator(app))
warning_handler.setLevel(logging.WARNING)
+ warning_handler.setFormatter(ColorizeFormatter())
logger.addHandler(info_handler)
logger.addHandler(warning_handler)
diff --git a/tests/test_util_logging.py b/tests/test_util_logging.py
index 6a4d0f315..7a7ce3b21 100644
--- a/tests/test_util_logging.py
+++ b/tests/test_util_logging.py
@@ -14,6 +14,7 @@ from docutils import nodes
from sphinx.errors import SphinxWarning
from sphinx.util import logging
+from sphinx.util.console import colorize
from sphinx.util.logging import is_suppressed_warning
from util import with_app, raises, strip_escseq
@@ -238,3 +239,33 @@ def test_pending_logging(app, status, warning):
# actually logged as ordered
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()