mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-07 05:31:15 -07:00
Initial Commit
This commit is contained in:
commit
88daa3fb91
1311 changed files with 256240 additions and 0 deletions
194
lib/logutils/colorize.py
Normal file
194
lib/logutils/colorize.py
Normal file
|
@ -0,0 +1,194 @@
|
|||
#
|
||||
# Copyright (C) 2010-2013 Vinay Sajip. All rights reserved.
|
||||
#
|
||||
import ctypes
|
||||
import logging
|
||||
import os
|
||||
|
||||
try:
|
||||
unicode
|
||||
except NameError:
|
||||
unicode = None
|
||||
|
||||
class ColorizingStreamHandler(logging.StreamHandler):
|
||||
"""
|
||||
A stream handler which supports colorizing of console streams
|
||||
under Windows, Linux and Mac OS X.
|
||||
|
||||
:param strm: The stream to colorize - typically ``sys.stdout``
|
||||
or ``sys.stderr``.
|
||||
"""
|
||||
|
||||
# color names to indices
|
||||
color_map = {
|
||||
'black': 0,
|
||||
'red': 1,
|
||||
'green': 2,
|
||||
'yellow': 3,
|
||||
'blue': 4,
|
||||
'magenta': 5,
|
||||
'cyan': 6,
|
||||
'white': 7,
|
||||
}
|
||||
|
||||
#levels to (background, foreground, bold/intense)
|
||||
if os.name == 'nt':
|
||||
level_map = {
|
||||
logging.DEBUG: (None, 'blue', True),
|
||||
logging.INFO: (None, 'white', False),
|
||||
logging.WARNING: (None, 'yellow', True),
|
||||
logging.ERROR: (None, 'red', True),
|
||||
logging.CRITICAL: ('red', 'white', True),
|
||||
}
|
||||
else:
|
||||
"Maps levels to colour/intensity settings."
|
||||
level_map = {
|
||||
logging.DEBUG: (None, 'blue', False),
|
||||
logging.INFO: (None, 'black', False),
|
||||
logging.WARNING: (None, 'yellow', False),
|
||||
logging.ERROR: (None, 'red', False),
|
||||
logging.CRITICAL: ('red', 'white', True),
|
||||
}
|
||||
|
||||
csi = '\x1b['
|
||||
reset = '\x1b[0m'
|
||||
|
||||
@property
|
||||
def is_tty(self):
|
||||
"Returns true if the handler's stream is a terminal."
|
||||
isatty = getattr(self.stream, 'isatty', None)
|
||||
return isatty and isatty()
|
||||
|
||||
def emit(self, record):
|
||||
try:
|
||||
message = self.format(record)
|
||||
stream = self.stream
|
||||
if unicode and isinstance(message, unicode):
|
||||
enc = getattr(stream, 'encoding', 'utf-8')
|
||||
message = message.encode(enc, 'replace')
|
||||
if not self.is_tty:
|
||||
stream.write(message)
|
||||
else:
|
||||
self.output_colorized(message)
|
||||
stream.write(getattr(self, 'terminator', '\n'))
|
||||
self.flush()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
self.handleError(record)
|
||||
|
||||
if os.name != 'nt':
|
||||
def output_colorized(self, message):
|
||||
"""
|
||||
Output a colorized message.
|
||||
|
||||
On Linux and Mac OS X, this method just writes the
|
||||
already-colorized message to the stream, since on these
|
||||
platforms console streams accept ANSI escape sequences
|
||||
for colorization. On Windows, this handler implements a
|
||||
subset of ANSI escape sequence handling by parsing the
|
||||
message, extracting the sequences and making Win32 API
|
||||
calls to colorize the output.
|
||||
|
||||
:param message: The message to colorize and output.
|
||||
"""
|
||||
self.stream.write(message)
|
||||
else:
|
||||
import re
|
||||
ansi_esc = re.compile(r'\x1b\[((?:\d+)(?:;(?:\d+))*)m')
|
||||
|
||||
nt_color_map = {
|
||||
0: 0x00, # black
|
||||
1: 0x04, # red
|
||||
2: 0x02, # green
|
||||
3: 0x06, # yellow
|
||||
4: 0x01, # blue
|
||||
5: 0x05, # magenta
|
||||
6: 0x03, # cyan
|
||||
7: 0x07, # white
|
||||
}
|
||||
|
||||
def output_colorized(self, message):
|
||||
"""
|
||||
Output a colorized message.
|
||||
|
||||
On Linux and Mac OS X, this method just writes the
|
||||
already-colorized message to the stream, since on these
|
||||
platforms console streams accept ANSI escape sequences
|
||||
for colorization. On Windows, this handler implements a
|
||||
subset of ANSI escape sequence handling by parsing the
|
||||
message, extracting the sequences and making Win32 API
|
||||
calls to colorize the output.
|
||||
|
||||
:param message: The message to colorize and output.
|
||||
"""
|
||||
parts = self.ansi_esc.split(message)
|
||||
write = self.stream.write
|
||||
h = None
|
||||
fd = getattr(self.stream, 'fileno', None)
|
||||
if fd is not None:
|
||||
fd = fd()
|
||||
if fd in (1, 2): # stdout or stderr
|
||||
h = ctypes.windll.kernel32.GetStdHandle(-10 - fd)
|
||||
while parts:
|
||||
text = parts.pop(0)
|
||||
if text:
|
||||
write(text)
|
||||
if parts:
|
||||
params = parts.pop(0)
|
||||
if h is not None:
|
||||
params = [int(p) for p in params.split(';')]
|
||||
color = 0
|
||||
for p in params:
|
||||
if 40 <= p <= 47:
|
||||
color |= self.nt_color_map[p - 40] << 4
|
||||
elif 30 <= p <= 37:
|
||||
color |= self.nt_color_map[p - 30]
|
||||
elif p == 1:
|
||||
color |= 0x08 # foreground intensity on
|
||||
elif p == 0: # reset to default color
|
||||
color = 0x07
|
||||
else:
|
||||
pass # error condition ignored
|
||||
ctypes.windll.kernel32.SetConsoleTextAttribute(h, color)
|
||||
|
||||
def colorize(self, message, record):
|
||||
"""
|
||||
Colorize a message for a logging event.
|
||||
|
||||
This implementation uses the ``level_map`` class attribute to
|
||||
map the LogRecord's level to a colour/intensity setting, which is
|
||||
then applied to the whole message.
|
||||
|
||||
:param message: The message to colorize.
|
||||
:param record: The ``LogRecord`` for the message.
|
||||
"""
|
||||
if record.levelno in self.level_map:
|
||||
bg, fg, bold = self.level_map[record.levelno]
|
||||
params = []
|
||||
if bg in self.color_map:
|
||||
params.append(str(self.color_map[bg] + 40))
|
||||
if fg in self.color_map:
|
||||
params.append(str(self.color_map[fg] + 30))
|
||||
if bold:
|
||||
params.append('1')
|
||||
if params:
|
||||
message = ''.join((self.csi, ';'.join(params),
|
||||
'm', message, self.reset))
|
||||
return message
|
||||
|
||||
def format(self, record):
|
||||
"""
|
||||
Formats a record for output.
|
||||
|
||||
This implementation colorizes the message line, but leaves
|
||||
any traceback unolorized.
|
||||
"""
|
||||
message = logging.StreamHandler.format(self, record)
|
||||
if self.is_tty:
|
||||
# Don't colorize any traceback
|
||||
parts = message.split('\n', 1)
|
||||
parts[0] = self.colorize(parts[0], record)
|
||||
message = '\n'.join(parts)
|
||||
return message
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue