web-dev-qa-db-ja.com

Pythonロギング出力に色を付けるにはどうすればよいですか?

少し前に、おそらくすべてのメッセージが標準化されていたために、おそらくログシステムのために、出力が色付きのMonoアプリケーションを見ました。

現在、Pythonにはloggingモジュールがあり、出力をカスタマイズするための多くのオプションを指定できます。したがって、Pythonで同様のことが可能になると想像していますが、どこでこれを行うかはわかりません。

Python loggingモジュールをカラーで出力する方法はありますか?

(たとえば)赤のエラー、青または黄色のデバッグメッセージなど。

もちろん、これにはおそらく互換性のある端末が必要になります(最新の端末のほとんどがそうです)。色がサポートされていない場合は、元のlogging出力にフォールバックできます。

ロギングモジュールで色付きの出力を取得する方法はありますか?

301
airmind

カラーエスケープについては既に知っていたので、しばらく前にbashプロンプトで使用しました。とにかくありがとう。
私が望んでいたのは、ロギングモジュールと統合することでした。最終的には、2、3回試行錯誤を繰り返しました。
これが私が最終的に得たものです。

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は、レコードオブジェクトを変更します。レコードオブジェクトは、他のハンドラーにさらに渡されるか、他のロガーに伝達されます。ファイルロガーなどを設定している場合は、おそらくログファイルに色を付けたくないでしょう。それを避けるには、おそらく、_name_name属性を操作する前にcopy.copy()recordのコピーを作成するか、フォーマットされた文字列を返す前にlevelnameを以前の値にリセットするのが最善です(クレジットは Michael コメント内)。

170
airmind

数年前、私は自分用にカラーストリームハンドラを作成しました。次に、このページに出会い、人々がコピー/貼り付けしているコードスニペットのコレクションを見つけました: 。私のストリームハンドラは現在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、ログレベル、およびログメッセージが含まれています。これは実際には次のようになります。

Screenshot of coloredlogs output

117
xolox

これは、どのプラットフォームでも機能するソリューションです。それだけで教えてくれない場合は更新します。

動作方法: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())
68
sorin

新しいクラスを定義せずに、事前に定義されたログレベル用の迅速でダーティなソリューション。

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

Update:これは私が長い間ひっかき続けることを意味していたかゆみなので、私は先に進み、私のような怠け者のためのライブラリを書きました物事を行う簡単な方法が必要な場合: 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")

出力:

Colorlog output

57
rlafuente

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

Colorlogモジュールがインストールされていて、出力が実際に端末に送られる場合、コードはログメッセージの色のみを有効にします。これにより、ログ出力のリダイレクト時にエスケープシーケンスがファイルに書き込まれるのを防ぎます。

また、背景が暗い端末に適したカスタムカラースキームが設定されています。

ロギングコールの例:

log.debug   ('Hello Debug')
log.info    ('Hello Info')
log.warn    ('Hello Warn')
log.error   ('Hello Error')
log.critical('Hello Critical')

出力:

enter image description here

14
maxschlepzig

前景と背景のタグをサポートする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
14
camillobruni

さて、色付きロガーのバリエーションを追加することも考えられます。

これは空想ではありませんが、使用するのが非常に簡単で、レコードオブジェクトを変更しないため、ファイルハンドラーが使用されている場合にANSIエスケープシーケンスをログファイルに記録することはありません。ログメッセージのフォーマットには影響しません。

すでに ロギングモジュールのFormatter を使用している場合、色付きのレベル名を取得するために行う必要があるのは、カウンセルハンドラーのFormatterを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")

結果

端末出力

Terminal output

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

13
KCJ

次のソリューションをご覧ください。ストリームハンドラーが色付けを行うものでなければなりません。その場合、行全体(Formatterを使用)ではなく単語を色付けするオプションがあります。

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

10
Nick

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

現在、カスタマイズ可能な色付きログ出力用のリリースされたPyPiモジュールがあります。

https://pypi.python.org/pypi/Rainbow_logging_handler/

そして

https://github.com/laysakura/Rainbow_logging_handler

  • Windowsをサポート

  • Djangoをサポート

  • カスタマイズ可能な色

これはPython Eggとして配布されるため、どのPythonアプリケーションにも簡単にインストールできます。

9
Mikko Ohtamaa

たくさんの回答があります。しかし、デコレータについて話しているものはありません。これが私のものです。

はるかに単純だからです。

何もインポートする必要も、サブクラスを作成する必要もありません。

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

すべてを1つのクラスに保持する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)
6
gravitation

任意の端末テキストを着色するためのシンプルだが非常に柔軟なツールは、「 colout 」です。

pip install colout
myprocess | colout REGEX_WITH_GROUPS color1,color2...

正規表現のグループ1に一致する「myprocess」の出力のテキストは、color1で色付けされ、グループ2はcolor2で色付けされます。

例えば:

tail -f /var/log/mylogfile | colout '^(\w+ \d+ [\d:]+)|(\w+\.py:\d+ .+\(\)): (.+)$' white,black,cyan bold,bold,normal

つまり、最初の正規表現グループ(かっこ)はログファイルの最初の日付に一致し、2番目のグループはpythonファイル名、行番号、関数名に一致し、3番目のグループはその後に続くログメッセージに一致します。また、「太字/法線」の並列シーケンスと色のシーケンスも使用します。これは次のようになります。

logfile with colored formatting

私の正規表現のいずれにも一致しない行または行の一部がまだエコーされることに注意してください。したがって、これは「grep --color」とは異なります-出力から何もフィルタリングされません。

これは明らかに、ログファイルの末尾だけでなく、あらゆるプロセスで使用できるほど十分に柔軟です。私は通常、何かを色付けしたいときはいつでもその場で新しい正規表現を作成します。このため、カスタムログファイルの色付けツールよりもcoloutの方が好きです。なぜなら、色付けするものに関係なく、1つのツールを学習するだけでよいからです。

また、ログファイル自体にANSIコードを実際にダンプすることも避けます。これは、grep正規表現のANSIコードと常に一致することを忘れない限り、ログファイル内のパターンのgrepのようなものを壊すためです。

5
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)))`
5
Serhii Khachko

私のソリューションは次のとおりです。

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

追加パッケージなしで簡単に追加できる2019フレッシュコード

クラスを定義する

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

結果enter image description here

2

私が問題を抱えていたのは、フォーマッタを適切にセットアップすることでした。

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
1
Nick

他のソリューションは問題ないようですが、いくつかの問題があります。時には望まれない行全体を色付けするものもあれば、すべてを一緒に持つ構成を省略するものもあります。以下の解決策は、メッセージ自体以外には影響しません。

コード

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に色コードを渡すだけです。

1
Pithikos

これは色コードを含む列挙です:

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'

これは、各ログレベルのnamesに適用できます。 これは巨大なハックであることに注意してください。

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
Joe Heffer

追加するサブミッションは2つあります。1つはメッセージだけを色付けするもの(ColoredFormatter)、もう1つは行全体を色付けするもの(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
ZetaSyanthis
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")

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__関数から1回呼び出します。私はそこにこのようなものがあります:

options, arguments = p.parse_args()
log_level = logging.DEBUG if options.verbose else logging.WARNING
config_log(log_level)

また、出力がコンソールであることを確認します。そうでない場合、色は使用されません。

0
yucer
0
herrk

pyfancy を使用します。

例:

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