3
3
from __future__ import division
4
4
from __future__ import print_function
5
5
6
+ import copy
6
7
import logging
7
8
import re
9
+ import sys
8
10
from contextlib import contextmanager
9
11
10
12
import py
19
21
DEFAULT_LOG_DATE_FORMAT = "%H:%M:%S"
20
22
21
23
22
- class ColoredLevelFormatter (logging .Formatter ):
24
+ class CustomFormatter (logging .Formatter ):
23
25
"""
24
- Colorize the %(levelname)..s part of the log format passed to __init__.
26
+ Colorize the %(levelname)..s part of the log format passed to __init__
27
+ and support proper aligning of multline log messages.
25
28
"""
26
29
27
30
LOGLEVEL_COLOROPTS = {
@@ -36,11 +39,7 @@ class ColoredLevelFormatter(logging.Formatter):
36
39
LEVELNAME_FMT_REGEX = re .compile (r"%\(levelname\)([+-]?\d*s)" )
37
40
38
41
def __init__ (self , terminalwriter , * args , ** kwargs ):
39
- super (ColoredLevelFormatter , self ).__init__ (* args , ** kwargs )
40
- if six .PY2 :
41
- self ._original_fmt = self ._fmt
42
- else :
43
- self ._original_fmt = self ._style ._fmt
42
+ super (CustomFormatter , self ).__init__ (* args , ** kwargs )
44
43
self ._level_to_fmt_mapping = {}
45
44
46
45
levelname_fmt_match = self .LEVELNAME_FMT_REGEX .search (self ._fmt )
@@ -62,13 +61,62 @@ def __init__(self, terminalwriter, *args, **kwargs):
62
61
colorized_formatted_levelname , self ._fmt
63
62
)
64
63
64
+ def formatMessage (self , record ):
65
+ fmt = self ._level_to_fmt_mapping .get (record .levelno , self ._fmt )
66
+
67
+ rdict = copy .copy (record .__dict__ )
68
+ # improve this hacky code, which calculates the
69
+ # 'continuation'-column for every record with a multiline message.
70
+ rdict ["message" ] = "MARKER"
71
+ logstr = self ._fmt % rdict
72
+ continuation_col = logstr .find ("MARKER" )
73
+ rdict ["message" ] = record .message
74
+
75
+ record .continuation_col = continuation_col
76
+ return fmt % rdict
77
+
65
78
def format (self , record ):
66
- fmt = self ._level_to_fmt_mapping .get (record .levelno , self ._original_fmt )
67
79
if six .PY2 :
68
- self . _fmt = fmt
80
+ fmtmessage = self . _format27 ( record )
69
81
else :
70
- self ._style ._fmt = fmt
71
- return super (ColoredLevelFormatter , self ).format (record )
82
+ fmtmessage = super (CustomFormatter , self ).format (record )
83
+
84
+ if "\n " in fmtmessage :
85
+ return ("\n " + record .continuation_col * " " ).join (fmtmessage .splitlines ())
86
+ return fmtmessage
87
+
88
+ def _format27 (self , record ):
89
+ """
90
+ Copied from stdlib version of logging.Formatter.format.
91
+
92
+ Use self.formatMessage instead of directly using old style str
93
+ formatting as used in the stdlib.
94
+ """
95
+ record .message = record .getMessage ()
96
+ if self .usesTime ():
97
+ record .asctime = self .formatTime (record , self .datefmt )
98
+
99
+ s = self .formatMessage (record )
100
+
101
+ if record .exc_info :
102
+ # Cache the traceback text to avoid converting it multiple times
103
+ # (it's constant anyway)
104
+ if not record .exc_text :
105
+ record .exc_text = self .formatException (record .exc_info )
106
+ if record .exc_text :
107
+ if s [- 1 :] != "\n " :
108
+ s = s + "\n "
109
+ try :
110
+ s = s + record .exc_text
111
+ except UnicodeError :
112
+ # Sometimes filenames have non-ASCII chars, which can lead
113
+ # to errors when s is Unicode and record.exc_text is str
114
+ # See issue 8924.
115
+ # We also use replace for when there are multiple
116
+ # encodings, e.g. UTF-8 for the filesystem and latin-1
117
+ # for a script. See issue 13232.
118
+ s = s + record .exc_text .decode (sys .getfilesystemencoding (), "replace" )
119
+ return s
72
120
73
121
74
122
def get_option_ini (config , * names ):
@@ -547,11 +595,8 @@ def _setup_cli_logging(self):
547
595
log_cli_date_format = get_option_ini (
548
596
self ._config , "log_cli_date_format" , "log_date_format"
549
597
)
550
- if (
551
- self ._config .option .color != "no"
552
- and ColoredLevelFormatter .LEVELNAME_FMT_REGEX .search (log_cli_format )
553
- ):
554
- log_cli_formatter = ColoredLevelFormatter (
598
+ if self ._config .option .color != "no" :
599
+ log_cli_formatter = CustomFormatter (
555
600
create_terminal_writer (self ._config ),
556
601
log_cli_format ,
557
602
datefmt = log_cli_date_format ,
0 commit comments