|
|
@ -7,7 +7,7 @@ import logging
|
|
|
|
import re
|
|
|
|
import re
|
|
|
|
import sys
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
from lib.core.settings import IS_WIN
|
|
|
|
from lib.core.settings import IS_WIN # 导入一个设置,用于判断是否在Windows系统上运行
|
|
|
|
|
|
|
|
|
|
|
|
if IS_WIN:
|
|
|
|
if IS_WIN:
|
|
|
|
import ctypes
|
|
|
|
import ctypes
|
|
|
@ -16,14 +16,15 @@ if IS_WIN:
|
|
|
|
# Reference: https://gist.github.com/vsajip/758430
|
|
|
|
# Reference: https://gist.github.com/vsajip/758430
|
|
|
|
# https://github.com/ipython/ipython/issues/4252
|
|
|
|
# https://github.com/ipython/ipython/issues/4252
|
|
|
|
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms686047%28v=vs.85%29.aspx
|
|
|
|
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms686047%28v=vs.85%29.aspx
|
|
|
|
|
|
|
|
# 设置Windows API函数SetConsoleTextAttribute的参数和返回值类型
|
|
|
|
ctypes.windll.kernel32.SetConsoleTextAttribute.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.WORD]
|
|
|
|
ctypes.windll.kernel32.SetConsoleTextAttribute.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.WORD]
|
|
|
|
ctypes.windll.kernel32.SetConsoleTextAttribute.restype = ctypes.wintypes.BOOL
|
|
|
|
ctypes.windll.kernel32.SetConsoleTextAttribute.restype = ctypes.wintypes.BOOL
|
|
|
|
|
|
|
|
|
|
|
|
def stdoutEncode(data): # Cross-referenced function
|
|
|
|
def stdoutEncode(data): # 用于编码标准输出数据的函数
|
|
|
|
return data
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
class ColorizingStreamHandler(logging.StreamHandler):
|
|
|
|
class ColorizingStreamHandler(logging.StreamHandler):
|
|
|
|
# color names to indices
|
|
|
|
# 定义颜色名称到索引的映射
|
|
|
|
color_map = {
|
|
|
|
color_map = {
|
|
|
|
'black': 0,
|
|
|
|
'black': 0,
|
|
|
|
'red': 1,
|
|
|
|
'red': 1,
|
|
|
@ -35,7 +36,7 @@ class ColorizingStreamHandler(logging.StreamHandler):
|
|
|
|
'white': 7,
|
|
|
|
'white': 7,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# levels to (background, foreground, bold/intense)
|
|
|
|
# 定义日志级别到颜色和样式的映射
|
|
|
|
level_map = {
|
|
|
|
level_map = {
|
|
|
|
logging.DEBUG: (None, 'blue', False),
|
|
|
|
logging.DEBUG: (None, 'blue', False),
|
|
|
|
logging.INFO: (None, 'green', False),
|
|
|
|
logging.INFO: (None, 'green', False),
|
|
|
@ -43,17 +44,19 @@ class ColorizingStreamHandler(logging.StreamHandler):
|
|
|
|
logging.ERROR: (None, 'red', False),
|
|
|
|
logging.ERROR: (None, 'red', False),
|
|
|
|
logging.CRITICAL: ('red', 'white', False)
|
|
|
|
logging.CRITICAL: ('red', 'white', False)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
csi = '\x1b['
|
|
|
|
csi = '\x1b[' # ANSI转义序列的前缀
|
|
|
|
reset = '\x1b[0m'
|
|
|
|
reset = '\x1b[0m' # ANSI重置颜色的转义序列
|
|
|
|
bold = "\x1b[1m"
|
|
|
|
bold = "\x1b[1m" # ANSI加粗的转义序列
|
|
|
|
disable_coloring = False
|
|
|
|
disable_coloring = False # 是否禁用颜色
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
@property
|
|
|
|
def is_tty(self):
|
|
|
|
def is_tty(self):
|
|
|
|
|
|
|
|
# 检查流是否是终端
|
|
|
|
isatty = getattr(self.stream, 'isatty', None)
|
|
|
|
isatty = getattr(self.stream, 'isatty', None)
|
|
|
|
return isatty and isatty() and not self.disable_coloring
|
|
|
|
return isatty and isatty() and not self.disable_coloring
|
|
|
|
|
|
|
|
|
|
|
|
def emit(self, record):
|
|
|
|
def emit(self, record):
|
|
|
|
|
|
|
|
# 发送日志记录
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
message = stdoutEncode(self.format(record))
|
|
|
|
message = stdoutEncode(self.format(record))
|
|
|
|
stream = self.stream
|
|
|
|
stream = self.stream
|
|
|
@ -76,9 +79,11 @@ class ColorizingStreamHandler(logging.StreamHandler):
|
|
|
|
|
|
|
|
|
|
|
|
if not IS_WIN:
|
|
|
|
if not IS_WIN:
|
|
|
|
def output_colorized(self, message):
|
|
|
|
def output_colorized(self, message):
|
|
|
|
|
|
|
|
# 如果不是Windows系统,直接写入消息
|
|
|
|
self.stream.write(message)
|
|
|
|
self.stream.write(message)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
ansi_esc = re.compile(r'\x1b\[((?:\d+)(?:;(?:\d+))*)m')
|
|
|
|
ansi_esc = re.compile(r'\x1b\[((?:\d+)(?:;(?:\d+))*)m')
|
|
|
|
|
|
|
|
# 正则表达式,用于匹配ANSI转义序列
|
|
|
|
|
|
|
|
|
|
|
|
nt_color_map = {
|
|
|
|
nt_color_map = {
|
|
|
|
0: 0x00, # black
|
|
|
|
0: 0x00, # black
|
|
|
@ -92,6 +97,7 @@ class ColorizingStreamHandler(logging.StreamHandler):
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def output_colorized(self, message):
|
|
|
|
def output_colorized(self, message):
|
|
|
|
|
|
|
|
# 如果是Windows系统,解析ANSI转义序列并设置控制台颜色
|
|
|
|
parts = self.ansi_esc.split(message)
|
|
|
|
parts = self.ansi_esc.split(message)
|
|
|
|
h = None
|
|
|
|
h = None
|
|
|
|
fd = getattr(self.stream, 'fileno', None)
|
|
|
|
fd = getattr(self.stream, 'fileno', None)
|
|
|
@ -131,9 +137,10 @@ class ColorizingStreamHandler(logging.StreamHandler):
|
|
|
|
ctypes.windll.kernel32.SetConsoleTextAttribute(h, color)
|
|
|
|
ctypes.windll.kernel32.SetConsoleTextAttribute(h, color)
|
|
|
|
|
|
|
|
|
|
|
|
def _reset(self, message):
|
|
|
|
def _reset(self, message):
|
|
|
|
|
|
|
|
# 如果消息不以重置序列结尾,则添加重置序列
|
|
|
|
if not message.endswith(self.reset):
|
|
|
|
if not message.endswith(self.reset):
|
|
|
|
reset = self.reset
|
|
|
|
reset = self.reset
|
|
|
|
elif self.bold in message: # bold
|
|
|
|
elif self.bold in message: # 如果消息包含加粗,则在重置后加粗
|
|
|
|
reset = self.reset + self.bold
|
|
|
|
reset = self.reset + self.bold
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
reset = self.reset
|
|
|
|
reset = self.reset
|
|
|
@ -141,6 +148,7 @@ class ColorizingStreamHandler(logging.StreamHandler):
|
|
|
|
return reset
|
|
|
|
return reset
|
|
|
|
|
|
|
|
|
|
|
|
def colorize(self, message, levelno):
|
|
|
|
def colorize(self, message, levelno):
|
|
|
|
|
|
|
|
# 根据日志级别给消息上色
|
|
|
|
if levelno in self.level_map and self.is_tty:
|
|
|
|
if levelno in self.level_map and self.is_tty:
|
|
|
|
bg, fg, bold = self.level_map[levelno]
|
|
|
|
bg, fg, bold = self.level_map[levelno]
|
|
|
|
params = []
|
|
|
|
params = []
|
|
|
@ -167,5 +175,6 @@ class ColorizingStreamHandler(logging.StreamHandler):
|
|
|
|
return message
|
|
|
|
return message
|
|
|
|
|
|
|
|
|
|
|
|
def format(self, record):
|
|
|
|
def format(self, record):
|
|
|
|
|
|
|
|
# 格式化日志记录
|
|
|
|
message = logging.StreamHandler.format(self, record)
|
|
|
|
message = logging.StreamHandler.format(self, record)
|
|
|
|
return self.colorize(message, record.levelno)
|
|
|
|
return self.colorize(message, record.levelno)
|
|
|
|