파이썬 로깅 출력을 어떻게 채색 할 수 있습니까?


352

얼마 전, 로그 시스템 때문에 모든 출력이 표준화 되었기 때문에 컬러 출력의 모노 응용 프로그램을 보았습니다.

이제 파이썬에는 logging모듈이 있는데,이를 통해 출력을 사용자 정의하기위한 많은 옵션을 지정할 수 있습니다. 그래서 파이썬에서 비슷한 것이 가능하다고 상상하지만 어디서나이 작업을 수행하는 방법을 찾을 수 없습니다.

파이썬 logging모듈을 컬러로 출력 하는 방법이 있습니까?

내가 원하는 것 (예를 들어) 빨간색으로 오류, 파란색 또는 노란색으로 메시지를 디버그하는 등.

물론 이것은 아마도 호환 가능한 터미널을 필요로 할 것입니다 (대부분의 최신 터미널은). logging색상이 지원되지 않으면 원래 출력으로 대체 될 수 있습니다.

로깅 모듈로 컬러 출력을 얻는 방법에 대한 아이디어가 있습니까?


1
Linux와 Windows 모두에서 멀티 플랫폼 솔루션을 원한다고 지정해야합니다.
sorin

1
: 이클립스 / PyDev에 사용하는 경우 관련 이클립스 콘솔 색상 화 로그
토비아스 Kienzler

5
아마도 당신은 또한 colorlog
Ehtesh Choudhury

5
모든 운영 체제 및 Python 버전 (2.7 및 3. *)을 지원하기 위해 작성한 크로마 로그 를 사용해 볼 수도 있습니다.
ereOn

1
실제로 로그 파일에 ANSI 코드를 덤프하는 솔루션은 나쁜 생각입니다. 6 개월 만에 무언가를 잡을 때 잡을 수 있지만 정규식 패턴에 ANSI 문자를 허용하는 것을 잊어 버립니다. 로그를 작성할 때가 아니라 로그를 볼 때 색상을 추가하는 몇 가지 솔루션이 있습니다.
Jonathan Hartley

답변:


192

나는 이미 색 이스케이프에 대해 알고 있었고 얼마 전에 내 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. 레코드 오브젝트를 변경하는 중입니다. 레코드 오브젝트는 다른 핸들러로 전달되거나 다른 로거로 전파됩니다. 파일 로거 등을 구성한 경우 로그 파일에 색상을 원하지 않을 수 있습니다. 이를 피하려면 , formatname 속성을 조작하기 전에 recordwith 의 사본을 작성 copy.copy()하거나 형식화 된 문자열 ( 주석에서 Michael 에게 신용)을 리턴하기 전에 levelname을 이전 값으로 재설정하는 것이 가장 좋습니다 .


노란색, 흰색, 파란색 등은 어디에 정의되어 있습니까?
Swaroop CH

1
@Swaroop-ANSI 이스케이프 코드는 Google에서 조회하거나 en.wikipedia.org/wiki/ANSI_escape_code 또는 pueblo.sourceforge.net/doc/manual/ansi_color_codes.html을 참조
Brian M

53
나는 이것을 위해 로거 서브 클래스를 만들어야한다고 생각하지 않습니다. 전문가를 만들고에 Formatter용도를 지정 하는 한 귀하의 대답은 좋습니다 StreamHandler. 그러나 로거 서브 클래스는 필요하지 않습니다. 실제로 로거 클래스를 사용하면 생성 된 모든 로거에 핸들러가 추가되는데, 이는 일반적으로 원하는 것이 아닙니다.
Vinay Sajip


6
한 쪽 참고 ColoredFormatter. 레코드 객체를 변경하여 다른 처리기로 전달되거나 다른 로거로 전파됩니다. 파일 로거 등을 구성한 경우 로그 파일에 색상을 원하지 않을 수 있습니다. 이를 피하려면 , formatname 속성을 조작하기 전에 recordwith 의 사본을 작성 copy.copy()하거나 형식화 된 문자열을 리턴하기 전에 levelname을 이전 값으로 재설정하는 것이 가장 좋습니다.
Michael

148

몇 년 전 나는 자신이 사용할 컬러 스트림 처리기를 썼습니다. 그런 다음이 페이지를 방문하여 사람들이 복사 / 붙여 넣는 코드 스 니펫 모음을 발견했습니다 .- (. 스트림 처리기는 현재 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, 로그 레벨 및 로그 메시지가 포함됩니다. 실제로는 다음과 같습니다.

coloredlogs 출력 스크린 샷

참고 : MinTTY와 함께 Git Bash를 사용하는 경우

Windows의 Git Bash에는 Winpty 및 Git Bash와 같은 문서화 된 단점이 있습니다.

ANSI 이스케이프 코드 및 ncurses 스타일 문자 재 작성 및 애니메이션의 경우 명령 앞에 접두사를 추가해야합니다 winpty.

$ winpty coloredlogs --demo
$ winpty python your_colored_logs_script.py

2
재미있게도, 이 글에서 " pypi.python.org/pypi/coloredlogs/0.4.7 " 링크를 추가하려고했습니다 !
Iosu S.

1
어떤 이유로 나는 사용할 AttributeError: 'module' object has no attribute 'install'때 계속 얻는다 coloredlogs.install(). 최신 버전으로 확인할 수 있습니까?
con-f-use

11
이것은 아름답게 보입니다. 불행히도 많은 것들을 망칩니다. 특히 logging.basicConfig에 대한 호출을 무효화합니다. 예를 들어, 사용자 정의 포맷터를 사용할 수 없습니다.
Clément

@ Clément : 두 가지 (중복?) 질문 : (1) "loging.basicConfig에 대한 호출을 무효화"한다는 것은 정확히 무엇을 의미하며 (2) 대안은 무엇입니까? 모두 logging.basicConfig()하고 coloredlogs.install()그래서 "무효화"없이 콘솔에 로그인하면 중복 메시지를받을 것이라고 스트림 처리기를 설치 ...
xolox

패키지 coloredlogs.install에서와 같이 (1)에 대한 마술이나 (더 합리적으로) 사용할 형식을 알려주는 방법을 기대했습니다 colorlog.
Clément

74

다음은 모든 플랫폼에서 작동해야하는 솔루션입니다. 그것이 단지 나에게 말하지 않으면 업데이트 할 것입니다.

작동 방식 : 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())

3
이를 기반으로 StreamHandler 클래스를 작성했습니다 ( gist.github.com/mooware/a1ed40987b6cc9ab9c65 참조) .
mooware

2
이것은 나를 위해 일했다! 90 행 :이어야합니다 args[1].msg = color + str(args[1].msg) + '\x1b[0m' # normal.
Rasika Perera

나는이 해결책을 좋아한다. 현재 사용 중입니다. _set_color 속성이 있는데 특정 로그 메시지에 대해 이것을 수행하는 방법이 있습니까? 편집 , 오, 그것은 단지 Windows 시스템을위한 패치 일뿐입니다. 다른 사용 사례에 대한 사용자 정의를 추가하는 것이 좋습니다.
brizz

ANSI 색상의 경우 +1 xterm에서는 한 번에 256 개의 색상을 얻을 수 있으며 팔레트를 동적으로 정의 할 수 있습니다! 그러나 함수 정의 외부에서 로그 할 때 잠재적 인 가져 오기 잠금 문제 를 피 하려면 로깅 함수에 대한 모든 호출 이 함수 정의 내에 있어야합니다 . 코드는 대부분 좋아 보인다. 조금만 TestColorer.py걱정이 되네요.
personal_cloud

실제 로그 파일의 로그 메시지 시작과 끝에 색상 코드가 나타납니다.
MehmedB

74

업데이트 : 이것은 오랫동안 스크래치로 생각했던 가려움증이기 때문에 간단한 방법으로 일을하고 싶은 저 같은 게으른 사람들을위한 라이브러리를 작성했습니다 .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")

산출:

컬러 로그 출력


4
큰 답변; +1. 그래도 코드 예제를 다듬을 수 있습니다 ( setLevel실제로 세 번의 호출 이 필요합니까?)
Clément

1
나는 충분히 오래 대답을 넘어 갔다면 이와 같은 대답을 찾았기를 바라고있었습니다. ☺ @airmind가 이것을 정답으로 만드는 것을 고려하여 미래의 일하는 똑똑한 사람들이 최적의 게으름을 갖춘 최고의 라이브러리 인 것을 찾을 수 있기를 바랍니다. 😉
Michael Scheper

나는 방금 OUTPUT의 메시지 예제를 위해
Agustin Barrachina

69

새 클래스를 정의하지 않고 사전 정의 된 로그 수준을위한 빠르고 더러운 솔루션입니다.

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))

@ spiderplant0 가져 오기 로깅; # @ABC의 코드를 붙여 넣습니다. logging.warning ( 'this is a test')으로 시도하십시오. "경고 : 테스트입니다"의 대문자 부분이 컬러로 표시됩니다. 그것은 단지 BTW 리눅스에서 작동
리카르도 갈리에게

3
로그 레벨 이름 만 색상이 지정되므로 로그 레벨 이름이 콘솔에 전혀 인쇄되어 있는지 확인해야합니다. 이것은 나를 위해 즉시 발생하지 않습니다. 이 라인을 따라 뭔가 도움이 될 것입니다 : logging.basicConfig(format='%(asctime)s [%(name)s] [%(levelname)s] %(message)s')물론 어디에서 %(levelnames)s중요합니다.
Sebastian

4
적용하고 이해하는 가장 간단하고 깨끗한 솔루션입니다.
F. Santiago

1
Linux 콘솔에서 시도하십시오. echo -e "Normal texst \033[1;31mred bold text\033[0m normal text again". echo -e옵션은 "\ 033"을 8 진수 형식의 이스케이프 ASCII 기호로 해석합니다. 이 특수 기호는 일부 호환 터미널이 후속 문자 (char m포함)를 특수 명령으로 해석하도록 합니다. en.wikipedia.org/wiki/ANSI_escape_code
eugene-bright

1
사소한 개선 :이 코드를 안에 넣습니다 if sys.sdterr.isatty():. 이 경우 출력을 파일로 리디렉션하면 파일에 이스케이프 문자가 포함되지 않습니다.
lesnik

35

2020 코드, 추가 패키지 불필요, 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")

결과 여기에 이미지 설명을 입력하십시오

풀 컬러 방식 여기에 이미지 설명을 입력하십시오

창문 용

이 솔루션은 Mac OS, IDE 터미널에서 작동합니다. 기본적으로 창의 명령 프롬프트에 색상이 전혀없는 것 같습니다. https://www.howtogeek.com/322432/how-to-customize-your-command-prompts-color-scheme-with-microsofts-colortool/을 시도하지 않은 방법을 활성화하는 방법은 다음과 같습니다.


1
테스트를 실행하지만 (파이썬 3.7, 윈도우) 로깅에 색상이 표시되지 않습니다.←[38;21m2019-11-12 19:29:50,994 - My_app - DEBUG - debug message (test_colored_log.py:43)←[0m ←[38;21m2019-11-12 19:29:50,994 - My_app - INFO - info message (test_colored_log.py:44)←[0m ←[33;21m2019-11-12 19:29:50,994 - My_app - WARNING - warning message (test_colored_log.py:45)←[0m ←[31;21m2019-11-12 19:29:50,994 - My_app - ERROR - error message (test_colored_log.py:46)←[0m ←[31;1m2019-11-12 19:29:50,994 - My_app - CRITICAL - critical message (test_colored_log.py:47)←[0m
생성자

불행히도 작동하지 않습니다.
Joe

2
나는이 답변을 너무 좋아서 몇 가지 증분과 ansi 색상의 치트 시트와 함께 repo 를 만들었습니다 .
Teodoro

@constructor 어디에서 실행합니까? IDE 콘솔? 윈도우 터미널?
Sergey Pleshakov

@Joe 정확히 작동하지 않는 것은 무엇입니까? 당신의 환경은 무엇이며 어떤 오류가 발생합니까? 여러 플랫폼에서 작동하도록 솔루션을 수정하고 싶습니다
Sergey Pleshakov

17

글쎄, 나는 컬러 로거의 변형을 추가 할 수도 있다고 생각합니다.

이것은 멋진 것은 아니지만 사용하기가 매우 쉽고 레코드 객체를 변경하지 않으므로 파일 핸들러가 사용되는 경우 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


2
BTW는 메시지 자체에 색상을 추가하기 전에 return다음 줄을 추가하기 만하면됩니다 .colored_record.msg = ('{0}{1}m{2}{3}').format(self.PREFIX, seq, colored_record.getMessage(), self.SUFFIX)
대부

15

전경 및 배경 태그를 지원하는 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

큰 개선. 그러나 의견은 super고대 파이썬 버전에만 적용됩니다. 이 답변은 2010 년 이후입니다. Python 2.7
Joakim

14

색상 표 모듈을 가져 와서 색상 화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')

산출:

여기에 이미지 설명을 입력하십시오


2
좋은 기본값 colorlog.basicConfiglogging.basicConfig있는 대신 사용할 수도 있습니다
MarSoft

1
레코드의 경우, 색상 로그가 항상 Windows 플랫폼에서 직접 작동하지는 않습니다 (지정된대로 색상 의존성이 필요함). 그럼에도 불구하고, 나는 Anaconda / Spyder env에서 작동하게하는 데 어려움을 겪었습니다. escape_code.py와 같이 colorama.init (strip = False)를 지정해야 할 수도 있습니다 (이 스레드 github.com/spyder-ide/spyder/issues/1917에 표시됨 )
Matt-Mac-Muffin

11

다음 해결책을보십시오. 스트림 핸들러는 채색을 수행하는 것이어야하며 (포맷터를 사용하여) 전체 줄 대신 단어를 채색하는 옵션이 있습니다.

http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html


요지 에서 업데이트 된 구현을 찾을 수 있습니다 (블로그 작성자가 유지 보수 함). 나는 그것을 사용하고 잘 작동합니다. 공유해 주셔서 감사합니다.
noisebleed

11

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)


7

많은 반응이 있습니다. 그러나 아무도 데코레이터에 대해 이야기하고 있지 않습니다. 여기 내 것이 있습니다.

훨씬 더 단순하기 때문입니다.

아무것도 가져 오거나 서브 클래스를 작성할 필요가 없습니다.

#!/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)

6

모든 것을 한 클래스에 유지하는 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)

5

모든 터미널 텍스트를 색칠하는 간단하지만 매우 유연한 도구는 ' 콜 아웃 '입니다.

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 코드와 항상 일치하는 것을 기억하지 않는 한 로그 파일의 패턴에 대한 grepping과 같은 것을 중단하기 때문에 나쁜 생각입니다.


4
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)))`

+1 [9*m"밝은"ANSI 색상 의 코드를 사용한 좋은 예 ! 추신 마지막 함수는 파이썬에서 함수 정의 외부에서 로깅하는 것이 안전한지 아직 알려지지 않았기 때문에 조금 관심 이 있습니다 .
personal_cloud

2

내 해결책은 다음과 같습니다.

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])

1

문제가있는 비트는 포맷터를 올바르게 설정하는 것이 었습니다.

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

의사 코드 (_set_colour가 누락 됨) 여야하지만 무언가를 추가했습니다. 가장 큰 문제는 포맷터를 올바르게 연결하는 방법을 아는 것이 었습니다.
Nick

"배관공 잭"솔루션을 참조하십시오. 나는 이것이 문제를 해결하는 더 좋은 방법이라고 생각합니다 (즉, 핸들러는 채색을해야합니다). stackoverflow.com/questions/384076/…
Nick

1

다른 솔루션은 문제가 없지만 몇 가지 문제가 있습니다. 일부는 원하지 않는 전체 라인을 색칠하고 일부는 함께 구성 할 수있는 구성을 생략합니다. 아래의 해결책은 메시지 자체에만 영향을 미치지 않습니다.

암호

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하려면 예제에서 색상 코드를 전달하면 됩니다.


사용하면 메시지가 두 번 인쇄됩니다. 왜 그런지 아십니까?
Validus Oculus

@ 정교하게 할 수 있습니까? 즉, 같은 [17:01:36]:WARNING:this should be yellowthis should be yellow줄 또는 전체 줄이 두 번 인쇄되는 것을 의미 합니까?
Pithikos

댓글을 간결하게해서 죄송합니다. 전자가 발생했습니다 : [17:01:36] : 경고 : 노란색이어야합니다 \ n 노란색이어야합니다. 그러나 형식이 지정된 것만 표시하고 싶습니다. 그렇지 않으면 중복 로그로 인해 가비지처럼 보입니다.
Validus Oculus

@ MuratKarakuş는 구현에 대한 완전한 견해를 보지 않고 왜 이런 일이 발생하는지 확실하지 않습니다. 사용자 정의 로거를 사용하는 경우 어느 시점에서 방해하고 있습니까? 빠른 수정이를 제거 할 수 7s:%(message)s로부터 log_format.
Pithikos

1

추가 할 두 개의 제출이 있는데, 그 중 하나는 메시지 (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


1

색상 코드가 포함 된 Enum입니다.

class TerminalColour:
    """
    Terminal colour formatting codes
    """
    # /programming/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'
        },

1

FriendlyLog 가 또 다른 대안입니다. Linux, Windows 및 MacOS에서 Python 2 및 3과 함께 작동합니다.


모듈 경로 혼란을 줄이기 위해 새로운 PR을 기대
mbspark

1

레벨별로 색상을 지정하는 것 외에도 색상을 번갈아 가면서 메시지 인수를 강조 표시하는 것은 어떻습니까? 최근에 간단한 코드를 작성했습니다. 또 다른 이점은 로그 호출이 Python 3 괄호 스타일 형식으로 작성된다는 것입니다. ( "{}").

https://github.com/davidohana/colargulog 에서 최신 코드 및 예제를 참조하십시오.

샘플 로깅 코드 :

root_logger = logging.getLogger()
console_handler = logging.StreamHandler(stream=sys.stdout)
console_format = "%(asctime)s - %(levelname)-8s - %(name)-25s - %(message)s"
colored_formatter = ColorizedArgsFormatter(console_format)
console_handler.setFormatter(colored_formatter)
root_logger.addHandler(console_handler)

logger = logging.getLogger(__name__)
logger.info("Hello World")
logger.info("Request from {} handled in {:.3f} ms", socket.gethostname(), 11)
logger.info("Request from {} handled in {:.3f} ms", "127.0.0.1", 33.1)
logger.info("My favorite drinks are {}, {}, {}, {}", "milk", "wine", "tea", "beer")
logger.debug("this is a {} message", logging.getLevelName(logging.DEBUG))
logger.info("this is a {} message", logging.getLevelName(logging.INFO))
logger.warning("this is a {} message", logging.getLevelName(logging.WARNING))
logger.error("this is a {} message", logging.getLevelName(logging.ERROR))
logger.critical("this is a {} message", logging.getLevelName(logging.CRITICAL))
logger.info("Does old-style formatting also work? %s it is, but no colors (yet)", True)

산출:

여기에 이미지 설명을 입력하십시오

이행:

"""
colargulog - Python3 Logging with Colored Arguments and new string formatting style

Written by david.ohana@ibm.com
License: Apache-2.0
"""

import logging
import logging.handlers
import re


class ColorCodes:
    grey = "\x1b[38;21m"
    green = "\x1b[1;32m"
    yellow = "\x1b[33;21m"
    red = "\x1b[31;21m"
    bold_red = "\x1b[31;1m"
    blue = "\x1b[1;34m"
    light_blue = "\x1b[1;36m"
    purple = "\x1b[1;35m"
    reset = "\x1b[0m"


class ColorizedArgsFormatter(logging.Formatter):
    arg_colors = [ColorCodes.purple, ColorCodes.light_blue]
    level_fields = ["levelname", "levelno"]
    level_to_color = {
        logging.DEBUG: ColorCodes.grey,
        logging.INFO: ColorCodes.green,
        logging.WARNING: ColorCodes.yellow,
        logging.ERROR: ColorCodes.red,
        logging.CRITICAL: ColorCodes.bold_red,
    }

    def __init__(self, fmt: str):
        super().__init__()
        self.level_to_formatter = {}

        def add_color_format(level: int):
            color = ColorizedArgsFormatter.level_to_color[level]
            _format = fmt
            for fld in ColorizedArgsFormatter.level_fields:
                search = "(%\(" + fld + "\).*?s)"
                _format = re.sub(search, f"{color}\\1{ColorCodes.reset}", _format)
            formatter = logging.Formatter(_format)
            self.level_to_formatter[level] = formatter

        add_color_format(logging.DEBUG)
        add_color_format(logging.INFO)
        add_color_format(logging.WARNING)
        add_color_format(logging.ERROR)
        add_color_format(logging.CRITICAL)

    @staticmethod
    def rewrite_record(record: logging.LogRecord):
        if not BraceFormatStyleFormatter.is_brace_format_style(record):
            return

        msg = record.msg
        msg = msg.replace("{", "_{{")
        msg = msg.replace("}", "_}}")
        placeholder_count = 0
        # add ANSI escape code for next alternating color before each formatting parameter
        # and reset color after it.
        while True:
            if "_{{" not in msg:
                break
            color_index = placeholder_count % len(ColorizedArgsFormatter.arg_colors)
            color = ColorizedArgsFormatter.arg_colors[color_index]
            msg = msg.replace("_{{", color + "{", 1)
            msg = msg.replace("_}}", "}" + ColorCodes.reset, 1)
            placeholder_count += 1

        record.msg = msg.format(*record.args)
        record.args = []

    def format(self, record):
        orig_msg = record.msg
        orig_args = record.args
        formatter = self.level_to_formatter.get(record.levelno)
        self.rewrite_record(record)
        formatted = formatter.format(record)

        # restore log record to original state for other handlers
        record.msg = orig_msg
        record.args = orig_args
        return formatted


class BraceFormatStyleFormatter(logging.Formatter):
    def __init__(self, fmt: str):
        super().__init__()
        self.formatter = logging.Formatter(fmt)

    @staticmethod
    def is_brace_format_style(record: logging.LogRecord):
        if len(record.args) == 0:
            return False

        msg = record.msg
        if '%' in msg:
            return False

        count_of_start_param = msg.count("{")
        count_of_end_param = msg.count("}")

        if count_of_start_param != count_of_end_param:
            return False

        if count_of_start_param != len(record.args):
            return False

        return True

    @staticmethod
    def rewrite_record(record: logging.LogRecord):
        if not BraceFormatStyleFormatter.is_brace_format_style(record):
            return

        record.msg = record.msg.format(*record.args)
        record.args = []

    def format(self, record):
        orig_msg = record.msg
        orig_args = record.args
        self.rewrite_record(record)
        formatted = self.formatter.format(record)

        # restore log record to original state for other handlers
        record.msg = orig_msg
        record.args = orig_args
        return formatted

0

pyfancy를 사용하십시오 .

예:

print(pyfancy.RED + "Hello Red!" + pyfancy.END)

문제는 logging별도의 채색 라이브러리를 사용 하도록 기능 을 조정하는 것이 었습니다 .
감염된 Drake

0

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)

또한 출력이 콘솔인지 확인하고, 그렇지 않으면 색상이 사용되지 않습니다.


0
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")


콘솔의 경우 파일 이름을 그대로 두거나 간단히 filename =``이 작동합니다. 파일 번호, 모듈 ..와 같은 다른 속성을 포함하도록 basicConfig를 수정하십시오.
estifanos gebrehiwot

0

다음 솔루션은 파이썬 3에서만 작동하지만 가장 명확하게 보입니다.

아이디어는 로그 레코드 팩토리를 사용하여 '컬러'속성을 로그 레코드 오브젝트에 추가하고 이러한 '컬러'속성을 로그 형식으로 사용하는 것입니다.

import logging
logger = logging.getLogger(__name__)

def configure_logging(level):

    # add 'levelname_c' attribute to log resords
    orig_record_factory = logging.getLogRecordFactory()
    log_colors = {
        logging.DEBUG:     "\033[1;34m",  # blue
        logging.INFO:      "\033[1;32m",  # green
        logging.WARNING:   "\033[1;35m",  # magenta
        logging.ERROR:     "\033[1;31m",  # red
        logging.CRITICAL:  "\033[1;41m",  # red reverted
    }
    def record_factory(*args, **kwargs):
        record = orig_record_factory(*args, **kwargs)
        record.levelname_c = "{}{}{}".format(
            log_colors[record.levelno], record.levelname, "\033[0m")
        return record

    logging.setLogRecordFactory(record_factory)

    # now each log record object would contain 'levelname_c' attribute
    # and you can use this attribute when configuring logging using your favorite
    # method.
    # for demo purposes I configure stderr log right here

    formatter_c = logging.Formatter("[%(asctime)s] %(levelname_c)s:%(name)s:%(message)s")

    stderr_handler = logging.StreamHandler()
    stderr_handler.setLevel(level)
    stderr_handler.setFormatter(formatter_c)

    root_logger = logging.getLogger('')
    root_logger.setLevel(logging.DEBUG)
    root_logger.addHandler(stderr_handler)


def main():
    configure_logging(logging.DEBUG)

    logger.debug("debug message")
    logger.info("info message")
    logger.critical("something unusual happened")


if __name__ == '__main__':
    main()

이 예제를 쉽게 수정하여 다른 컬러 속성 (fe message_c)을 만든 다음이 속성을 사용하여 원하는 곳에 컬러 텍스트를 가져올 수 있습니다.

(최근에 내가 발견 한 유용한 트릭 : 색상이 지정된 디버그 로그가있는 파일이 있으며 일시적으로 응용 프로그램의 로그 수준을 높이고 싶을 때마다 tail -f다른 터미널의 로그 파일 만 있고 구성을 변경하고 응용 프로그램을 다시 시작하지 않고 화면의 디버그 로그를 볼 수 있습니다 )


0

이것은 airmind 예제의 또 다른 Python3 변형입니다. 다른 예제에서는 볼 수없는 특정 기능을 원했습니다.

  • 터미널에는 색상을 사용하지만 파일 핸들러에는 인쇄 할 수없는 문자를 쓰지 않습니다 (2 개의 포맷터를 정의했습니다)
  • 특정 로그 메시지의 색상을 재정의하는 기능
  • 파일에서 로거 구성 (이 경우 yaml)

참고 : colorama를 사용 했지만 필요하지 않으므로 수정할 수 있습니다. 또한 내 테스트를 위해 방금 파이썬 파일을 실행 중이므로 클래스가 모듈에 있습니다. 모듈이 무엇이든 __main__변경 (): __main__.ColoredFormatter해야합니다.

pip install colorama pyyaml

logging.yaml

---
version: 1
disable_existing_loggers: False
formatters:
  simple:
    format: "%(threadName)s - %(name)s - %(levelname)s - %(message)s"
  color:
    format: "%(threadName)s - %(name)s - %(levelname)s - %(message)s"
    (): __main__.ColoredFormatter
    use_color: true

handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: color
    stream: ext://sys.stdout

  info_file_handler:
    class: logging.handlers.RotatingFileHandler
    level: INFO
    formatter: simple
    filename: app.log
    maxBytes: 20971520 
    backupCount: 20
    encoding: utf8

  error_file_handler:
    class: logging.handlers.RotatingFileHandler
    level: ERROR
    formatter: simple
    filename: errors.log
    maxBytes: 10485760 
    backupCount: 20
    encoding: utf8

root:
  level: DEBUG
  handlers: [console, info_file_handler, error_file_handler]

main.py

import logging
import logging.config
import os
from logging import Logger

import colorama
import yaml
from colorama import Back, Fore, Style

COLORS = {
    "WARNING": Fore.YELLOW,
    "INFO": Fore.CYAN,
    "DEBUG": Fore.BLUE,
    "CRITICAL": Fore.YELLOW,
    "ERROR": Fore.RED,
}


class ColoredFormatter(logging.Formatter):
    def __init__(self, *, format, use_color):
        logging.Formatter.__init__(self, fmt=format)
        self.use_color = use_color

    def format(self, record):
        msg = super().format(record)
        if self.use_color:
            levelname = record.levelname
            if hasattr(record, "color"):
                return f"{record.color}{msg}{Style.RESET_ALL}"
            if levelname in COLORS:
                return f"{COLORS[levelname]}{msg}{Style.RESET_ALL}"
        return msg


with open("logging.yaml", "rt") as f:
    config = yaml.safe_load(f.read())
    logging.config.dictConfig(config)

logger: Logger = logging.getLogger(__name__)
logger.info("Test INFO", extra={"color": Back.RED})
logger.info("Test INFO", extra={"color": f"{Style.BRIGHT}{Back.RED}"})
logger.info("Test INFO")
logger.debug("Test DEBUG")
logger.warning("Test WARN")

산출:

산출

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.