2
# Copyright (C) 2010-2013 Vinay Sajip. All rights reserved.
13
class ColorizingStreamHandler(logging.StreamHandler):
15
A stream handler which supports colorizing of console streams
16
under Windows, Linux and Mac OS X.
18
:param strm: The stream to colorize - typically ``sys.stdout``
22
# color names to indices
34
#levels to (background, foreground, bold/intense)
37
logging.DEBUG: (None, 'blue', True),
38
logging.INFO: (None, 'white', False),
39
logging.WARNING: (None, 'yellow', True),
40
logging.ERROR: (None, 'red', True),
41
logging.CRITICAL: ('red', 'white', True),
44
"Maps levels to colour/intensity settings."
46
logging.DEBUG: (None, 'blue', False),
47
logging.INFO: (None, 'black', False),
48
logging.WARNING: (None, 'yellow', False),
49
logging.ERROR: (None, 'red', False),
50
logging.CRITICAL: ('red', 'white', True),
58
"Returns true if the handler's stream is a terminal."
59
isatty = getattr(self.stream, 'isatty', None)
60
return isatty and isatty()
62
def emit(self, record):
64
message = self.format(record)
66
if unicode and isinstance(message, unicode):
67
enc = getattr(stream, 'encoding', 'utf-8')
68
message = message.encode(enc, 'replace')
72
self.output_colorized(message)
73
stream.write(getattr(self, 'terminator', '\n'))
75
except (KeyboardInterrupt, SystemExit):
78
self.handleError(record)
81
def output_colorized(self, message):
83
Output a colorized message.
85
On Linux and Mac OS X, this method just writes the
86
already-colorized message to the stream, since on these
87
platforms console streams accept ANSI escape sequences
88
for colorization. On Windows, this handler implements a
89
subset of ANSI escape sequence handling by parsing the
90
message, extracting the sequences and making Win32 API
91
calls to colorize the output.
93
:param message: The message to colorize and output.
95
self.stream.write(message)
98
ansi_esc = re.compile(r'\x1b\[((?:\d+)(?:;(?:\d+))*)m')
111
def output_colorized(self, message):
113
Output a colorized message.
115
On Linux and Mac OS X, this method just writes the
116
already-colorized message to the stream, since on these
117
platforms console streams accept ANSI escape sequences
118
for colorization. On Windows, this handler implements a
119
subset of ANSI escape sequence handling by parsing the
120
message, extracting the sequences and making Win32 API
121
calls to colorize the output.
123
:param message: The message to colorize and output.
125
parts = self.ansi_esc.split(message)
126
write = self.stream.write
128
fd = getattr(self.stream, 'fileno', None)
131
if fd in (1, 2): # stdout or stderr
132
h = ctypes.windll.kernel32.GetStdHandle(-10 - fd)
138
params = parts.pop(0)
140
params = [int(p) for p in params.split(';')]
144
color |= self.nt_color_map[p - 40] << 4
146
color |= self.nt_color_map[p - 30]
148
color |= 0x08 # foreground intensity on
149
elif p == 0: # reset to default color
152
pass # error condition ignored
153
ctypes.windll.kernel32.SetConsoleTextAttribute(h, color)
155
def colorize(self, message, record):
157
Colorize a message for a logging event.
159
This implementation uses the ``level_map`` class attribute to
160
map the LogRecord's level to a colour/intensity setting, which is
161
then applied to the whole message.
163
:param message: The message to colorize.
164
:param record: The ``LogRecord`` for the message.
166
if record.levelno in self.level_map:
167
bg, fg, bold = self.level_map[record.levelno]
169
if bg in self.color_map:
170
params.append(str(self.color_map[bg] + 40))
171
if fg in self.color_map:
172
params.append(str(self.color_map[fg] + 30))
176
message = ''.join((self.csi, ';'.join(params),
177
'm', message, self.reset))
180
def format(self, record):
182
Formats a record for output.
184
This implementation colorizes the message line, but leaves
185
any traceback unolorized.
187
message = logging.StreamHandler.format(self, record)
189
# Don't colorize any traceback
190
parts = message.split('\n', 1)
191
parts[0] = self.colorize(parts[0], record)
192
message = '\n'.join(parts)