파이썬 로깅 출력을 어떻게 채색 할 수 있습니까?
얼마 전, 로그 시스템 때문에 모든 출력이 표준화 되었기 때문에 컬러 출력의 모노 응용 프로그램을 보았습니다.
이제 파이썬에는 logging
모듈이 있는데,이를 통해 출력을 사용자 정의하기위한 많은 옵션을 지정할 수 있습니다. 그래서 파이썬에서 비슷한 것이 가능하다고 상상하지만 어디서나이 작업을 수행하는 방법을 찾을 수 없습니다.
파이썬 logging
모듈을 컬러로 출력 하는 방법이 있습니까?
내가 원하는 것 (예를 들어) 빨간색으로 오류, 파란색 또는 노란색으로 메시지를 디버그하는 등.
물론 이것은 아마도 호환 가능한 터미널을 필요로 할 것입니다 (대부분의 최신 터미널은). logging
색상이 지원되지 않으면 원래 출력으로 대체 될 수 있습니다.
로깅 모듈로 컬러 출력을 얻는 방법에 대한 아이디어가 있습니까?
나는 이미 색 이스케이프에 대해 알고 있었고, 얼마 전에 bash 프롬프트에서 사용했습니다. 어쨌든 고마워
내가 원했던 것은 로깅 모듈과 통합하는 것이 었습니다. 로깅 모듈은 결국 몇 번의 시도와 오류 후에 수행되었습니다.
내가 끝내는 것은 다음과 같습니다.
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
#The background is set with 40 plus the number of the color, and the foreground with 30
#These are the sequences need to get colored ouput
RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"
def formatter_message(message, use_color = True):
if use_color:
message = message.replace("$RESET", RESET_SEQ).replace("$BOLD", BOLD_SEQ)
else:
message = message.replace("$RESET", "").replace("$BOLD", "")
return message
COLORS = {
'WARNING': YELLOW,
'INFO': WHITE,
'DEBUG': BLUE,
'CRITICAL': YELLOW,
'ERROR': RED
}
class ColoredFormatter(logging.Formatter):
def __init__(self, msg, use_color = True):
logging.Formatter.__init__(self, msg)
self.use_color = use_color
def format(self, record):
levelname = record.levelname
if self.use_color and levelname in COLORS:
levelname_color = COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ
record.levelname = levelname_color
return logging.Formatter.format(self, record)
그리고 그것을 사용하려면 자신의 로거를 만드십시오.
# Custom logger class with multiple destinations
class ColoredLogger(logging.Logger):
FORMAT = "[$BOLD%(name)-20s$RESET][%(levelname)-18s] %(message)s ($BOLD%(filename)s$RESET:%(lineno)d)"
COLOR_FORMAT = formatter_message(FORMAT, True)
def __init__(self, name):
logging.Logger.__init__(self, name, logging.DEBUG)
color_formatter = ColoredFormatter(self.COLOR_FORMAT)
console = logging.StreamHandler()
console.setFormatter(color_formatter)
self.addHandler(console)
return
logging.setLoggerClass(ColoredLogger)
다른 사람이 필요할 경우를 대비하여.
하나 이상의 로거 또는 핸들러를 사용하는 경우주의하십시오 ColoredFormatter
. 레코드 오브젝트를 변경하면 다른 핸들러로 전달되거나 다른 로거로 전파됩니다. 파일 로거 등을 구성한 경우 로그 파일에 색상을 원하지 않을 수 있습니다. 이를 피하려면 levelname 속성을 조작하기 전에 record
with 의 사본을 작성 copy.copy()
하거나 형식화 된 문자열 ( 주석에서 Michael 에게 신용)을 리턴하기 전에 levelname을 이전 값으로 재설정하는 것이 가장 좋습니다 .
몇 년 전 나는 자신이 사용할 컬러 스트림 처리기를 썼습니다. 그런 다음이 페이지를 방문하여 사람들이 복사 / 붙여 넣는 코드 스 니펫 모음을 찾았습니다 .- (. 스트림 처리기는 현재 UNIX (Linux, Mac OS X)에서만 작동하지만 이점은 PyPI (및 GitHub) 에서 사용할 수 있다는 것입니다 ) 그리고 사용하기 간단하고 Vim 구문 모드도 있습니다 :-). 앞으로 Windows에서 작동하도록 확장 할 수 있습니다.
패키지를 설치하려면
$ pip install coloredlogs
작동하는지 확인하려면 다음을 수행하십시오.
$ coloredlogs --demo
자신의 코드로 시작하려면
$ python
> import coloredlogs, logging
> coloredlogs.install()
> logging.info("It works!")
2014-07-30 21:21:26 peter-macbook root[7471] INFO It works!
위 예에 표시된 기본 로그 형식에는 날짜, 시간, 호스트 이름, 로거 이름, PID, 로그 레벨 및 로그 메시지가 포함됩니다. 실제로는 다음과 같습니다.
다음은 모든 플랫폼에서 작동해야하는 솔루션입니다. 그것이 단지 나에게 말하지 않으면 업데이트 할 것입니다.
작동 방식 : ANSI 이스케이프를 지원하는 플랫폼에서는 Windows를 사용하지 않고 Windows에서는 콘솔 호출을 변경하기 위해 API 호출을 사용합니다.
스크립트는 래퍼를 추가하는 표준 라이브러리에서 logging.StreamHandler.emit 메소드를 해킹합니다.
TestColorer.py
# Usage: add Colorer.py near you script and import it.
import logging
import Colorer
logging.warn("a warning")
logging.error("some error")
logging.info("some info")
Colorer.py
#!/usr/bin/env python
# encoding: utf-8
import logging
# now we patch Python code to add color support to logging.StreamHandler
def add_coloring_to_emit_windows(fn):
# add methods we need to the class
def _out_handle(self):
import ctypes
return ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE)
out_handle = property(_out_handle)
def _set_color(self, code):
import ctypes
# Constants from the Windows API
self.STD_OUTPUT_HANDLE = -11
hdl = ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE)
ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, code)
setattr(logging.StreamHandler, '_set_color', _set_color)
def new(*args):
FOREGROUND_BLUE = 0x0001 # text color contains blue.
FOREGROUND_GREEN = 0x0002 # text color contains green.
FOREGROUND_RED = 0x0004 # text color contains red.
FOREGROUND_INTENSITY = 0x0008 # text color is intensified.
FOREGROUND_WHITE = FOREGROUND_BLUE|FOREGROUND_GREEN |FOREGROUND_RED
# winbase.h
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
# wincon.h
FOREGROUND_BLACK = 0x0000
FOREGROUND_BLUE = 0x0001
FOREGROUND_GREEN = 0x0002
FOREGROUND_CYAN = 0x0003
FOREGROUND_RED = 0x0004
FOREGROUND_MAGENTA = 0x0005
FOREGROUND_YELLOW = 0x0006
FOREGROUND_GREY = 0x0007
FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified.
BACKGROUND_BLACK = 0x0000
BACKGROUND_BLUE = 0x0010
BACKGROUND_GREEN = 0x0020
BACKGROUND_CYAN = 0x0030
BACKGROUND_RED = 0x0040
BACKGROUND_MAGENTA = 0x0050
BACKGROUND_YELLOW = 0x0060
BACKGROUND_GREY = 0x0070
BACKGROUND_INTENSITY = 0x0080 # background color is intensified.
levelno = args[1].levelno
if(levelno>=50):
color = BACKGROUND_YELLOW | FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY
elif(levelno>=40):
color = FOREGROUND_RED | FOREGROUND_INTENSITY
elif(levelno>=30):
color = FOREGROUND_YELLOW | FOREGROUND_INTENSITY
elif(levelno>=20):
color = FOREGROUND_GREEN
elif(levelno>=10):
color = FOREGROUND_MAGENTA
else:
color = FOREGROUND_WHITE
args[0]._set_color(color)
ret = fn(*args)
args[0]._set_color( FOREGROUND_WHITE )
#print "after"
return ret
return new
def add_coloring_to_emit_ansi(fn):
# add methods we need to the class
def new(*args):
levelno = args[1].levelno
if(levelno>=50):
color = '\x1b[31m' # red
elif(levelno>=40):
color = '\x1b[31m' # red
elif(levelno>=30):
color = '\x1b[33m' # yellow
elif(levelno>=20):
color = '\x1b[32m' # green
elif(levelno>=10):
color = '\x1b[35m' # pink
else:
color = '\x1b[0m' # normal
args[1].msg = color + args[1].msg + '\x1b[0m' # normal
#print "after"
return fn(*args)
return new
import platform
if platform.system()=='Windows':
# Windows does not support ANSI escapes and we are using API calls to set the console color
logging.StreamHandler.emit = add_coloring_to_emit_windows(logging.StreamHandler.emit)
else:
# all non-Windows platforms are supporting ANSI escapes so we use them
logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)
#log = logging.getLogger()
#log.addFilter(log_filter())
#//hdlr = logging.StreamHandler()
#//hdlr.setFormatter(formatter())
새 클래스를 정의하지 않고 사전 정의 된 로그 수준을위한 빠르고 더러운 솔루션입니다.
logging.addLevelName( logging.WARNING, "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.WARNING))
logging.addLevelName( logging.ERROR, "\033[1;41m%s\033[1;0m" % logging.getLevelName(logging.ERROR))
업데이트 : 이것은 오랫동안 스크래치로 생각했던 가려움증이기 때문에 간단한 방법으로 일을하고 싶은 저 같은 게으른 사람들을위한 라이브러리를 작성했습니다 .zenlog
Colorlog는 이것에 탁월합니다. PyPI 에서 사용할 수 있으며이를 통해 설치할 수 pip install colorlog
있으며 적극적으로 유지 관리 됩니다.
다음은 로깅을 설정하고보기 좋은 로그 메시지를 인쇄하는 빠른 복사 및 붙여 넣기가 가능한 스 니펫입니다.
import logging
LOG_LEVEL = logging.DEBUG
LOGFORMAT = " %(log_color)s%(levelname)-8s%(reset)s | %(log_color)s%(message)s%(reset)s"
from colorlog import ColoredFormatter
logging.root.setLevel(LOG_LEVEL)
formatter = ColoredFormatter(LOGFORMAT)
stream = logging.StreamHandler()
stream.setLevel(LOG_LEVEL)
stream.setFormatter(formatter)
log = logging.getLogger('pythonConfig')
log.setLevel(LOG_LEVEL)
log.addHandler(stream)
log.debug("A quirky message only developers care about")
log.info("Curious users might want to know this")
log.warn("Something is wrong and any user should be informed")
log.error("Serious stuff, this is red for a reason")
log.critical("OH NO everything is on fire")
산출:
전경 및 배경 태그를 지원하는 airmind에서 예제를 업데이트했습니다. 로그 포맷터 문자열에 색상 변수 $ BLACK-$ WHITE를 사용하십시오. 배경을 설정하려면 $ BG-BLACK-$ BG-WHITE를 사용하십시오.
import logging
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
COLORS = {
'WARNING' : YELLOW,
'INFO' : WHITE,
'DEBUG' : BLUE,
'CRITICAL' : YELLOW,
'ERROR' : RED,
'RED' : RED,
'GREEN' : GREEN,
'YELLOW' : YELLOW,
'BLUE' : BLUE,
'MAGENTA' : MAGENTA,
'CYAN' : CYAN,
'WHITE' : WHITE,
}
RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"
class ColorFormatter(logging.Formatter):
def __init__(self, *args, **kwargs):
# can't do super(...) here because Formatter is an old school class
logging.Formatter.__init__(self, *args, **kwargs)
def format(self, record):
levelname = record.levelname
color = COLOR_SEQ % (30 + COLORS[levelname])
message = logging.Formatter.format(self, record)
message = message.replace("$RESET", RESET_SEQ)\
.replace("$BOLD", BOLD_SEQ)\
.replace("$COLOR", color)
for k,v in COLORS.items():
message = message.replace("$" + k, COLOR_SEQ % (v+30))\
.replace("$BG" + k, COLOR_SEQ % (v+40))\
.replace("$BG-" + k, COLOR_SEQ % (v+40))
return message + RESET_SEQ
logging.ColorFormatter = ColorFormatter
이제 설정 파일에서 다음을 간단하게 수행 할 수 있습니다.
[formatter_colorFormatter]
class=logging.ColorFormatter
format= $COLOR%(levelname)s $RESET %(asctime)s $BOLD$COLOR%(name)s$RESET %(message)s
글쎄, 나는 컬러 로거의 변형을 추가 할 수도 있다고 생각합니다.
이것은 멋진 것은 아니지만 사용이 매우 간단하고 레코드 객체를 변경하지 않으므로 파일 핸들러가 사용되는 경우 ANSI 이스케이프 시퀀스를 로그 파일에 기록하지 않습니다. 로그 메시지 형식에는 영향을 미치지 않습니다.
로깅 모듈의 포맷터를 이미 사용중인 경우 색상 레벨 이름을 얻으려면 상담원 핸들러 포맷터를 ColoredFormatter로 바꾸면됩니다. 전체 앱을 로깅하는 경우 최상위 로거에 대해서만이 작업을 수행하면됩니다.
colored_log.py
#!/usr/bin/env python
from copy import copy
from logging import Formatter
MAPPING = {
'DEBUG' : 37, # white
'INFO' : 36, # cyan
'WARNING' : 33, # yellow
'ERROR' : 31, # red
'CRITICAL': 41, # white on red bg
}
PREFIX = '\033['
SUFFIX = '\033[0m'
class ColoredFormatter(Formatter):
def __init__(self, patern):
Formatter.__init__(self, patern)
def format(self, record):
colored_record = copy(record)
levelname = colored_record.levelname
seq = MAPPING.get(levelname, 37) # default white
colored_levelname = ('{0}{1}m{2}{3}') \
.format(PREFIX, seq, levelname, SUFFIX)
colored_record.levelname = colored_levelname
return Formatter.format(self, colored_record)
사용법 예
app.py
#!/usr/bin/env python
import logging
from colored_log import ColoredFormatter
# Create top level logger
log = logging.getLogger("main")
# Add console handler using our custom ColoredFormatter
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
cf = ColoredFormatter("[%(name)s][%(levelname)s] %(message)s (%(filename)s:%(lineno)d)")
ch.setFormatter(cf)
log.addHandler(ch)
# Add file handler
fh = logging.FileHandler('app.log')
fh.setLevel(logging.DEBUG)
ff = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(ff)
log.addHandler(fh)
# Set log level
log.setLevel(logging.DEBUG)
# Log some stuff
log.debug("app has started")
log.info("Logging to 'app.log' in the script dir")
log.warning("This is my last warning, take heed")
log.error("This is an error")
log.critical("He's dead, Jim")
# Import a sub-module
import sub_module
sub_module.py
#!/usr/bin/env python
import logging
log = logging.getLogger('main.sub_module')
log.debug("Hello from the sub module")
결과
터미널 출력
app.log 컨텐츠
2017-09-29 00:32:23,434 - main - DEBUG - app has started
2017-09-29 00:32:23,434 - main - INFO - Logging to 'app.log' in the script dir
2017-09-29 00:32:23,435 - main - WARNING - This is my last warning, take heed
2017-09-29 00:32:23,435 - main - ERROR - This is an error
2017-09-29 00:32:23,435 - main - CRITICAL - He's dead, Jim
2017-09-29 00:32:23,435 - main.sub_module - DEBUG - Hello from the sub module
물론 터미널 및 로그 파일 출력 형식을 지정하면 원하는대로 표현할 수 있습니다. 로그 레벨 만 색상이 지정됩니다.
누군가가 이것을 유용하게 사용하기를 희망하며 너무 많은 것이 아닙니다. :)
Python 예제 파일은 다음 GitHub Gist에서 다운로드 할 수 있습니다. https://gist.github.com/KurtJacobson/48e750701acec40c7161b5a2f79e6bfd
colorlog 모듈을 가져 와서 ColoredFormatter
로그 메시지를 채색 하는 데 사용할 수 있습니다 .
예
메인 모듈 용 보일러 플레이트 :
import logging
import os
import sys
try:
import colorlog
except ImportError:
pass
def setup_logging():
root = logging.getLogger()
root.setLevel(logging.DEBUG)
format = '%(asctime)s - %(levelname)-8s - %(message)s'
date_format = '%Y-%m-%d %H:%M:%S'
if 'colorlog' in sys.modules and os.isatty(2):
cformat = '%(log_color)s' + format
f = colorlog.ColoredFormatter(cformat, date_format,
log_colors = { 'DEBUG' : 'reset', 'INFO' : 'reset',
'WARNING' : 'bold_yellow', 'ERROR': 'bold_red',
'CRITICAL': 'bold_red' })
else:
f = logging.Formatter(format, date_format)
ch = logging.StreamHandler()
ch.setFormatter(f)
root.addHandler(ch)
setup_logging()
log = logging.getLogger(__name__)
이 코드는 컬러 로그 모듈이 설치되어 있고 출력이 실제로 터미널로가는 경우에만 로그 메시지에서 컬러를 활성화합니다. 이렇게하면 로그 출력이 경로 재 지정 될 때 이스케이프 시퀀스가 파일에 기록되지 않습니다.
또한 배경이 어두운 터미널에 더 적합한 사용자 지정 색 구성표가 설정됩니다.
로깅 호출 예 :
log.debug ('Hello Debug')
log.info ('Hello Info')
log.warn ('Hello Warn')
log.error ('Hello Error')
log.critical('Hello Critical')
산출:
Sorin이 제공 한 원본 예제와 하위 클래스 인 StreamHandler를 ColorizedConsoleHandler로 수정했습니다.
솔루션의 단점은 메시지를 수정한다는 것입니다. 실제 로그 메시지를 수정하기 때문에 다른 핸들러도 수정 된 메시지를받습니다.
우리는 여러 로거를 사용하기 때문에 우리의 경우 색상 코드가있는 로그 파일이 생성되었습니다.
아래 클래스는 ansi를 지원하는 플랫폼에서만 작동하지만 Windows 색상 코드를 추가하는 것은 쉽지 않습니다.
import copy
import logging
class ColoredConsoleHandler(logging.StreamHandler):
def emit(self, record):
# Need to make a actual copy of the record
# to prevent altering the message for other loggers
myrecord = copy.copy(record)
levelno = myrecord.levelno
if(levelno >= 50): # CRITICAL / FATAL
color = '\x1b[31m' # red
elif(levelno >= 40): # ERROR
color = '\x1b[31m' # red
elif(levelno >= 30): # WARNING
color = '\x1b[33m' # yellow
elif(levelno >= 20): # INFO
color = '\x1b[32m' # green
elif(levelno >= 10): # DEBUG
color = '\x1b[35m' # pink
else: # NOTSET and anything else
color = '\x1b[0m' # normal
myrecord.msg = color + str(myrecord.msg) + '\x1b[0m' # normal
logging.StreamHandler.emit(self, myrecord)
다음 해결책을보십시오. 스트림 핸들러는 채색을 수행하는 것이어야하며 (포맷터를 사용하여) 전체 줄 대신 단어를 채색하는 옵션이 있습니다.
http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html
이제 사용자 정의 가능한 컬러 로깅 출력을위한 PyPi 모듈이 출시되었습니다.
https://pypi.python.org/pypi/rainbow_logging_handler/
과
https://github.com/laysakura/rainbow_logging_handler
Windows 지원
장고 지원
맞춤형 색상
이것은 Python egg로 배포되므로 모든 Python 응용 프로그램에 설치하기가 매우 쉽습니다.
많은 반응이 있습니다. 그러나 아무도 데코레이터에 대해 이야기하고 있지 않습니다. 여기 내 것이 있습니다.
훨씬 더 단순하기 때문입니다.
아무것도 가져 오거나 하위 클래스를 작성할 필요가 없습니다.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
NO_COLOR = "\33[m"
RED, GREEN, ORANGE, BLUE, PURPLE, LBLUE, GREY = \
map("\33[%dm".__mod__, range(31, 38))
logging.basicConfig(format="%(message)s", level=logging.DEBUG)
logger = logging.getLogger(__name__)
# the decorator to apply on the logger methods info, warn, ...
def add_color(logger_method, color):
def wrapper(message, *args, **kwargs):
return logger_method(
# the coloring is applied here.
color+message+NO_COLOR,
*args, **kwargs
)
return wrapper
for level, color in zip((
"info", "warn", "error", "debug"), (
GREEN, ORANGE, RED, BLUE
)):
setattr(logger, level, add_color(getattr(logger, level), color))
# this is displayed in red.
logger.error("Launching %s." % __file__)
이렇게하면 오류가 빨간색으로 설정되고 디버그 메시지가 파란색으로 설정됩니다. 질문 에서처럼.
래퍼를 color
사용하여 메시지의 색상을 동적으로 설정 하는 인수를 취할 수도 있습니다.logger.debug("message", color=GREY)
편집 : 런타임에 색상을 설정하기 위해 적용된 데코레이터는 다음과 같습니다.
def add_color(logger_method, _color):
def wrapper(message, *args, **kwargs):
color = kwargs.pop("color", _color)
if isinstance(color, int):
color = "\33[%dm" % color
return logger_method(
# the coloring is applied here.
color+message+NO_COLOR,
*args, **kwargs
)
return wrapper
# blah blah, apply the decorator...
# this is displayed in red.
logger.error("Launching %s." % __file__)
# this is displayed in blue
logger.error("Launching %s." % __file__, color=34)
# and this, in grey
logger.error("Launching %s." % __file__, color=GREY)
모든 것을 한 클래스에 유지하는 airmind 접근 방식의 또 다른 사소한 리믹스 :
class ColorFormatter(logging.Formatter):
FORMAT = ("[$BOLD%(name)-20s$RESET][%(levelname)-18s] "
"%(message)s "
"($BOLD%(filename)s$RESET:%(lineno)d)")
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"
COLORS = {
'WARNING': YELLOW,
'INFO': WHITE,
'DEBUG': BLUE,
'CRITICAL': YELLOW,
'ERROR': RED
}
def formatter_msg(self, msg, use_color = True):
if use_color:
msg = msg.replace("$RESET", self.RESET_SEQ).replace("$BOLD", self.BOLD_SEQ)
else:
msg = msg.replace("$RESET", "").replace("$BOLD", "")
return msg
def __init__(self, use_color=True):
msg = self.formatter_msg(self.FORMAT, use_color)
logging.Formatter.__init__(self, msg)
self.use_color = use_color
def format(self, record):
levelname = record.levelname
if self.use_color and levelname in self.COLORS:
fore_color = 30 + self.COLORS[levelname]
levelname_color = self.COLOR_SEQ % fore_color + levelname + self.RESET_SEQ
record.levelname = levelname_color
return logging.Formatter.format(self, record)
포맷터를 핸들러에 연결하려면 다음과 같이 처리하십시오.
handler.setFormatter(ColorFormatter())
logger.addHandler(handler)
import logging
import sys
colors = {'pink': '\033[95m', 'blue': '\033[94m', 'green': '\033[92m', 'yellow': '\033[93m', 'red': '\033[91m',
'ENDC': '\033[0m', 'bold': '\033[1m', 'underline': '\033[4m'}
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
def str_color(color, data):
return colors[color] + str(data) + colors['ENDC']
params = {'param1': id1, 'param2': id2}
logging.info('\nParams:' + str_color("blue", str(params)))`
모든 터미널 텍스트를 색칠하는 간단하지만 매우 유연한 도구는 ' 콜 아웃 '입니다.
pip install colout
myprocess | colout REGEX_WITH_GROUPS color1,color2...
정규식의 그룹 1과 일치하는 'myprocess'출력의 텍스트에 색상 1, 그룹 2에 색상 2 등이 표시됩니다.
예를 들면 다음과 같습니다.
tail -f /var/log/mylogfile | colout '^(\w+ \d+ [\d:]+)|(\w+\.py:\d+ .+\(\)): (.+)$' white,black,cyan bold,bold,normal
즉, 첫 번째 정규식 그룹 (parens)은 로그 파일의 초기 날짜와 일치하고 두 번째 그룹은 python 파일 이름, 줄 번호 및 함수 이름과 일치하고 세 번째 그룹은 그 이후에 오는 로그 메시지와 일치합니다. 나는 또한 색상 시퀀스뿐만 아니라 'bold / normals'의 병렬 시퀀스를 사용합니다. 이것은 다음과 같습니다
내 정규 표현식과 일치하지 않는 선이나 선의 일부가 여전히 에코되므로 'grep --color'와 같지 않습니다. 출력에서 아무것도 필터링되지 않습니다.
분명히 이것은 테일링 로그 파일뿐만 아니라 모든 프로세스에서 사용할 수있을 정도로 유연합니다. 나는 보통 무언가를 색칠하고 싶을 때마다 즉시 새로운 정규 표현식을 채 웁니다. 이러한 이유로, 나는 채색하는 것에 관계없이 로깅, 테스트 출력, 터미널의 구문 강조 코드 조각 등 하나의 도구 만 배우면되기 때문에 모든 사용자 정의 로그 파일 채색 도구를 선호합니다.
또한 실제로 로그 파일 자체에 ANSI 코드를 덤프하지 않도록합니다. IMHO는 그레프 정규식에서 ANSI 코드와 항상 일치하는 것을 기억하지 않는 한 로그 파일의 패턴을 파기하는 것과 같은 문제를 야기 할 수 있습니다.
2019 코드, 추가 패키지 불필요, Python 3
클래스 정의
import logging
class CustomFormatter(logging.Formatter):
"""Logging Formatter to add colors and count warning / errors"""
grey = "\x1b[38;21m"
yellow = "\x1b[33;21m"
red = "\x1b[31;21m"
bold_red = "\x1b[31;1m"
reset = "\x1b[0m"
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)"
FORMATS = {
logging.DEBUG: grey + format + reset,
logging.INFO: grey + format + reset,
logging.WARNING: yellow + format + reset,
logging.ERROR: red + format + reset,
logging.CRITICAL: bold_red + format + reset
}
def format(self, record):
log_fmt = self.FORMATS.get(record.levelno)
formatter = logging.Formatter(log_fmt)
return formatter.format(record)
로거 인스턴스화
# create logger with 'spam_application'
logger = logging.getLogger("My_app")
logger.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(CustomFormatter())
logger.addHandler(ch)
그리고 사용하십시오!
logger.debug("debug message")
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
logger.critical("critical message")
내 해결책은 다음과 같습니다.
class ColouredFormatter(logging.Formatter):
RESET = '\x1B[0m'
RED = '\x1B[31m'
YELLOW = '\x1B[33m'
BRGREEN = '\x1B[01;32m' # grey in solarized for terminals
def format(self, record, colour=False):
message = super().format(record)
if not colour:
return message
level_no = record.levelno
if level_no >= logging.CRITICAL:
colour = self.RED
elif level_no >= logging.ERROR:
colour = self.RED
elif level_no >= logging.WARNING:
colour = self.YELLOW
elif level_no >= logging.INFO:
colour = self.RESET
elif level_no >= logging.DEBUG:
colour = self.BRGREEN
else:
colour = self.RESET
message = colour + message + self.RESET
return message
class ColouredHandler(logging.StreamHandler):
def __init__(self, stream=sys.stdout):
super().__init__(stream)
def format(self, record, colour=False):
if not isinstance(self.formatter, ColouredFormatter):
self.formatter = ColouredFormatter()
return self.formatter.format(record, colour)
def emit(self, record):
stream = self.stream
try:
msg = self.format(record, stream.isatty())
stream.write(msg)
stream.write(self.terminator)
self.flush()
except Exception:
self.handleError(record)
h = ColouredHandler()
h.formatter = ColouredFormatter('{asctime} {levelname:8} {message}', '%Y-%m-%d %H:%M:%S', '{')
logging.basicConfig(level=logging.DEBUG, handlers=[h])
문제가있는 비트는 포맷터를 올바르게 설정하는 것이 었습니다.
class ColouredFormatter(logging.Formatter):
def __init__(self, msg):
logging.Formatter.__init__(self, msg)
self._init_colour = _get_colour()
def close(self):
# restore the colour information to what it was
_set_colour(self._init_colour)
def format(self, record):
# Add your own colourer based on the other examples
_set_colour( LOG_LEVEL_COLOUR[record.levelno] )
return logging.Formatter.format(self, record)
def init():
# Set up the formatter. Needs to be first thing done.
rootLogger = logging.getLogger()
hdlr = logging.StreamHandler()
fmt = ColouredFormatter('%(message)s')
hdlr.setFormatter(fmt)
rootLogger.addHandler(hdlr)
그런 다음 사용하십시오.
import coloured_log
import logging
coloured_log.init()
logging.info("info")
logging.debug("debug")
coloured_log.close() # restore colours
다른 솔루션은 문제가 없지만 몇 가지 문제가 있습니다. 일부는 원하지 않는 전체 라인을 색칠하고 일부는 함께 구성 할 수있는 구성을 생략합니다. 아래의 해결책은 메시지 자체에는 영향을 미치지 않습니다.
암호
class ColoredFormatter(logging.Formatter):
def format(self, record):
if record.levelno == logging.WARNING:
record.msg = '\033[93m%s\033[0m' % record.msg
elif record.levelno == logging.ERROR:
record.msg = '\033[91m%s\033[0m' % record.msg
return logging.Formatter.format(self, record)
예
logger = logging.getLogger('mylogger')
handler = logging.StreamHandler()
log_format = '[%(asctime)s]:%(levelname)-7s:%(message)s'
time_format = '%H:%M:%S'
formatter = ColoredFormatter(log_format, datefmt=time_format)
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.warn('this should be yellow')
logger.error('this should be red')
산출
[17:01:36]:WARNING:this should be yellow
[17:01:37]:ERROR :this should be red
보시다시피, 다른 모든 것은 여전히 출력되고 초기 색상으로 유지됩니다. 메시지 이외의 다른 것을 변경 log_format
하려면 예제에서 색상 코드를 전달하면 됩니다.
추가 할 두 개의 제출이 있는데, 그 중 하나는 메시지 (ColoredFormatter) 만 채색하고 다른 하나는 전체 줄 (ColorizingStreamHandler)을 채색합니다. 여기에는 이전 솔루션보다 더 많은 ANSI 색상 코드가 포함됩니다.
일부 컨텐츠는 위의 게시물 및 http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html 에서 수정되었습니다 .
메시지 만 채색합니다.
class ColoredFormatter(logging.Formatter):
"""Special custom formatter for colorizing log messages!"""
BLACK = '\033[0;30m'
RED = '\033[0;31m'
GREEN = '\033[0;32m'
BROWN = '\033[0;33m'
BLUE = '\033[0;34m'
PURPLE = '\033[0;35m'
CYAN = '\033[0;36m'
GREY = '\033[0;37m'
DARK_GREY = '\033[1;30m'
LIGHT_RED = '\033[1;31m'
LIGHT_GREEN = '\033[1;32m'
YELLOW = '\033[1;33m'
LIGHT_BLUE = '\033[1;34m'
LIGHT_PURPLE = '\033[1;35m'
LIGHT_CYAN = '\033[1;36m'
WHITE = '\033[1;37m'
RESET = "\033[0m"
def __init__(self, *args, **kwargs):
self._colors = {logging.DEBUG: self.DARK_GREY,
logging.INFO: self.RESET,
logging.WARNING: self.BROWN,
logging.ERROR: self.RED,
logging.CRITICAL: self.LIGHT_RED}
super(ColoredFormatter, self).__init__(*args, **kwargs)
def format(self, record):
"""Applies the color formats"""
record.msg = self._colors[record.levelno] + record.msg + self.RESET
return logging.Formatter.format(self, record)
def setLevelColor(self, logging_level, escaped_ansi_code):
self._colors[logging_level] = escaped_ansi_code
전체 라인을 채색합니다.
class ColorizingStreamHandler(logging.StreamHandler):
BLACK = '\033[0;30m'
RED = '\033[0;31m'
GREEN = '\033[0;32m'
BROWN = '\033[0;33m'
BLUE = '\033[0;34m'
PURPLE = '\033[0;35m'
CYAN = '\033[0;36m'
GREY = '\033[0;37m'
DARK_GREY = '\033[1;30m'
LIGHT_RED = '\033[1;31m'
LIGHT_GREEN = '\033[1;32m'
YELLOW = '\033[1;33m'
LIGHT_BLUE = '\033[1;34m'
LIGHT_PURPLE = '\033[1;35m'
LIGHT_CYAN = '\033[1;36m'
WHITE = '\033[1;37m'
RESET = "\033[0m"
def __init__(self, *args, **kwargs):
self._colors = {logging.DEBUG: self.DARK_GREY,
logging.INFO: self.RESET,
logging.WARNING: self.BROWN,
logging.ERROR: self.RED,
logging.CRITICAL: self.LIGHT_RED}
super(ColorizingStreamHandler, self).__init__(*args, **kwargs)
@property
def is_tty(self):
isatty = getattr(self.stream, 'isatty', None)
return isatty and isatty()
def emit(self, record):
try:
message = self.format(record)
stream = self.stream
if not self.is_tty:
stream.write(message)
else:
message = self._colors[record.levelno] + message + self.RESET
stream.write(message)
stream.write(getattr(self, 'terminator', '\n'))
self.flush()
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)
def setLevelColor(self, logging_level, escaped_ansi_code):
self._colors[logging_level] = escaped_ansi_code
색상 코드가 포함 된 Enum입니다.
class TerminalColour:
"""
Terminal colour formatting codes
"""
# https://stackoverflow.com/questions/287871/print-in-terminal-with-colors
MAGENTA = '\033[95m'
BLUE = '\033[94m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
GREY = '\033[0m' # normal
WHITE = '\033[1m' # bright white
UNDERLINE = '\033[4m'
이는 각 로그 레벨 의 이름 에 적용될 수 있습니다 . 이것은 엄청난 해킹입니다.
logging.addLevelName(logging.INFO, "{}{}{}".format(TerminalColour.WHITE, logging.getLevelName(logging.INFO), TerminalColour.GREY))
logging.addLevelName(logging.WARNING, "{}{}{}".format(TerminalColour.YELLOW, logging.getLevelName(logging.WARNING), TerminalColour.GREY))
logging.addLevelName(logging.ERROR, "{}{}{}".format(TerminalColour.RED, logging.getLevelName(logging.ERROR), TerminalColour.GREY))
logging.addLevelName(logging.CRITICAL, "{}{}{}".format(TerminalColour.MAGENTA, logging.getLevelName(logging.CRITICAL), .GREY))
로그 포맷터는 로그 레벨의 이름을 포함해야합니다.
%(levelname)
예를 들면 다음과 같습니다.
LOGGING = {
...
'verbose': {
'format': '%(asctime)s %(levelname)s %(name)s:%(lineno)s %(module)s %(process)d %(thread)d %(message)s'
},
'simple': {
'format': '[%(asctime)s] %(levelname)s %(name)s %(message)s'
},
pyfancy를 사용하십시오 .
예:
print(pyfancy.RED + "Hello Red!" + pyfancy.END)
ZetaSyanthis의 색상을 가진 또 다른 솔루션 :
def config_log(log_level):
def set_color(level, code):
level_fmt = "\033[1;" + str(code) + "m%s\033[1;0m"
logging.addLevelName( level, level_fmt % logging.getLevelName(level) )
std_stream = sys.stdout
isatty = getattr(std_stream, 'isatty', None)
if isatty and isatty():
levels = [logging.DEBUG, logging.CRITICAL, logging.WARNING, logging.ERROR]
for idx, level in enumerate(levels):
set_color(level, 30 + idx )
set_color(logging.DEBUG, 0)
logging.basicConfig(stream=std_stream, level=log_level)
__main__
함수 에서 한 번 호출하십시오 . 나는 이것과 같은 것을 가지고있다 :
options, arguments = p.parse_args()
log_level = logging.DEBUG if options.verbose else logging.WARNING
config_log(log_level)
또한 출력이 콘솔인지 확인하고, 그렇지 않으면 색상이 사용되지 않습니다.
import logging
logging.basicConfig(filename="f.log" filemode='w', level=logging.INFO,
format = "%(logger_name)s %(color)s %(message)s %(endColor)s")
class Logger(object):
__GREEN = "\033[92m"
__RED = '\033[91m'
__ENDC = '\033[0m'
def __init__(self, name):
self.logger = logging.getLogger(name)
self.extra={'logger_name': name, 'endColor': self.__ENDC, 'color': self.__GREEN}
def info(self, msg):
self.extra['color'] = self.__GREEN
self.logger.info(msg, extra=self.extra)
def error(self, msg):
self.extra['color'] = self.__RED
self.logger.error(msg, extra=self.extra)
용법
Logger("File Name").info("This shows green text")
FriendlyLog 가 또 다른 대안입니다. Linux, Windows 및 MacOS에서 Python 2 및 3과 함께 작동합니다.
비슷한 질문에 대해 똑같이 대답했습니다 : Python | 쉘에서 텍스트 색상 변경
아이디어는 클린트 라이브러리 를 사용하는 것입니다 . MAC, Linux 및 Windows 셸 (CLI)을 지원합니다.
참고 URL : https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output
'Programing' 카테고리의 다른 글
다른 필드의 값을 사용하여 MongoDB 필드 업데이트 (0) | 2020.03.08 |
---|---|
패키지 폴더를 무시하도록 TFS 받기 (0) | 2020.03.08 |
HTML 태그에 사용자 정의 속성을 추가 할 수 있습니까? (0) | 2020.03.08 |
안드로이드 에뮬레이터는 키보드 입력을받지 않습니다-SDK tools rev 20 (0) | 2020.03.08 |
mapDispatchToProps 란 무엇입니까? (0) | 2020.03.08 |