23

ここでpython 2 についてこの質問をしましたが、答えが Python 3.2.3 で機能しなくなったときに、再び問題にぶつかりました。

Python 2.7.3 で動作するコードは次のとおりです。

import logging

# Attempt to set up a Python3 logger than will print custom messages
# based on each message's logging level.
# The technique recommended for Python2 does not appear to work for
# Python3

class CustomConsoleFormatter(logging.Formatter):
    """
    Modify the way DEBUG messages are displayed.

    """
    def __init__(self, fmt="%(levelno)d: %(msg)s"):
        logging.Formatter.__init__(self, fmt=fmt)

    def format(self, record):

        # Remember the original format
        format_orig = self._fmt

        if record.levelno == logging.DEBUG:
            self._fmt = "DEBUG: %(msg)s"

        # Call the original formatter to do the grunt work
        result = logging.Formatter.format(self, record)

        # Restore the original format
        self._fmt = format_orig

        return result


# Set up a logger
my_logger = logging.getLogger("my_custom_logger")
my_logger.setLevel(logging.DEBUG)

my_formatter = CustomConsoleFormatter()

console_handler = logging.StreamHandler()
console_handler.setFormatter(my_formatter)

my_logger.addHandler(console_handler)

my_logger.debug("This is a DEBUG-level message")
my_logger.info("This is an INFO-level message")

Python 2.7.3 を使用した実行:

tcsh-16: python demo_python_2.7.3.py 
DEBUG: This is a DEBUG-level message
20: This is an INFO-level message


私の知る限り、Python3 への変換には、CustomConsoleFormatter へのわずかな変更のみが必要です。初期化():

def __init__(self):
    super().__init__(fmt="%(levelno)d: %(msg)s", datefmt=None, style='%')

Python 3.2.3 の場合:

tcsh-26: python3 demo_python_3.2.3.py
10: This is a DEBUG-level message
20: This is an INFO-level message


ご覧のとおり、'10' を 'DEBUG' に置き換えたいという私の願望が妨げられています。

私はPython3ソースを掘り下げてみましたが、PercentStyleのインスタンス化がself._fmtを壊しているように見えます。

私のロギングチョップは、このしわを回避できるようになる直前に停止します。

誰かが別の方法を推奨したり、私が見落としていることを指摘したりできますか?

4

7 に答える 7

25

少し掘り下げて、Python2ソリューションをPython3で動作するように変更することができました。Python2では、一時的に上書きする必要がありましたFormatter._fmt。Python3では、複数のフォーマット文字列タイプをサポートするには、Formatter._style._fmt代わりに一時的に上書きする必要があります。

# Custom formatter
class MyFormatter(logging.Formatter):

    err_fmt  = "ERROR: %(msg)s"
    dbg_fmt  = "DBG: %(module)s: %(lineno)d: %(msg)s"
    info_fmt = "%(msg)s"

    def __init__(self):
        super().__init__(fmt="%(levelno)d: %(msg)s", datefmt=None, style='%')  
    
    def format(self, record):

        # Save the original format configured by the user
        # when the logger formatter was instantiated
        format_orig = self._style._fmt

        # Replace the original format with one customized by logging level
        if record.levelno == logging.DEBUG:
            self._style._fmt = MyFormatter.dbg_fmt

        elif record.levelno == logging.INFO:
            self._style._fmt = MyFormatter.info_fmt

        elif record.levelno == logging.ERROR:
            self._style._fmt = MyFormatter.err_fmt

        # Call the original formatter class to do the grunt work
        result = logging.Formatter.format(self, record)

        # Restore the original format configured by the user
        self._style._fmt = format_orig

        return result

そして、これがあなたのスクリプトで上記を使用する方法のHalloleoの例です(この質問のPython2バージョンから):

fmt = MyFormatter()
hdlr = logging.StreamHandler(sys.stdout)

hdlr.setFormatter(fmt)
logging.root.addHandler(hdlr)
logging.root.setLevel(logging.DEBUG)
于 2013-02-13T17:37:40.260 に答える
2

別の回答の相互投稿。logging.Formatter書式設定スタイルに依存する新しい実装 (現時点では 3.2+、3.4) のため、機能しません。'{'これはスタイル形式に依存しますが、適応させることができます。より一般的になるように洗練され、書式設定スタイルとカスタム メッセージを へ__init__の引数として選択できるようにすることもできます。

class SpecialFormatter(logging.Formatter):
    FORMATS = {logging.DEBUG : logging._STYLES['{']("{module} DEBUG: {lineno}: {message}"),
           logging.ERROR : logging._STYLES['{']("{module} ERROR: {message}"),
           logging.INFO : logging._STYLES['{']("{module}: {message}"),
           'DEFAULT' : logging._STYLES['{']("{module}: {message}")}

    def format(self, record):
        # Ugly. Should be better
        self._style = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT'])
        return logging.Formatter.format(self, record)

hdlr = logging.StreamHandler(sys.stderr)
hdlr.setFormatter(SpecialFormatter())
logging.root.addHandler(hdlr)
logging.root.setLevel(logging.INFO)
于 2013-05-21T20:20:55.667 に答える
1

私はこの質問に遅れて沈黙していますが、これが私の解決策です。元の python 2 構文スタイルに従います。一般に、スタイルのサポートが追加されたため、使用する必要がある 3 つの新しいクラスがあります。それらは、PercentStyle、StrFormatStyle、および StringTemplateStyle です。

from logging import Formatter, PercentStyle, ERROR, WARNING, INFO, DEBUG
class SrvLogFormat(Formatter):
    def __init__(self):
        super().__init__(fmt=env.fmt_log, datefmt=env.fmt_log_date)

    def format(self, record):
        original_style = self._style

        if record.levelno == DEBUG:
            self._style = PercentStyle(env.fmt_dflt)
        if record.levelno == INFO:
            self._style = PercentStyle(env.fmt_dflt)
        if record.levelno == WARNING:
            self._style = PercentStyle(env.fmt_dflt)
        if record.levelno == ERROR:
            self._style = PercentStyle(env.fmt_err)

        result = Formatter.format(self, record)
        self._style = original_style
        return result
于 2016-04-14T15:53:23.323 に答える