3

Python ロギング モジュールを使用して、ホスト名などの他の情報を記録し、DB に追加するカスタム ログ ファイルを作成しようとしています。以下は、これを行うために作成したクラスです。ハンドラー部分は問題なく動作していましたが、カスタムLogRecordクラスを追加したため、次のエラーがスローされます。

/src/lib/__init__.py", line 31, in __init__
logging.LogRecord.__init__(self, *args, **kwargs)
exceptions.TypeError: __init__() takes at most 9 arguments (10 given)

そして、これが私がそれを実行する方法です

logging.setLoggerClass(MyLogger)

log = logging.getLogger('testing')
log.addHandler(MyLogHandler())
d = {'host': '192.168.0.1'}
log.warn('Hi', d)    

そして、ここにクラスがあります。明らかに*args、**kwargsと関係がありますが、私がそれを見ると、*argsは空で、**kwargsにはd上記で指定された変数しか含まれていません。問題がわかりません。

class MyLogRecord(logging.LogRecord):
    def __init__(self, *args, **kwargs):
        logging.LogRecord.__init__(self, *args, **kwargs) //THIS IS THE LINE IT DIES ON
        self.host = 'localhost'

class MyLogFormatter(logging.Formatter):

    def __init__(self, fmt, datefmt=None, host=None):
        logging.Formatter.__init__(self, fmt, datefmt)
        self.host = host

    def format(self, record):
        return logging.Formatter.format(record)

class MyLogger(logging.getLoggerClass()):
    def makeRecord(self, *args, **kwargs):
        return MyLogRecord(*args, **kwargs)

class MyLogHandler(logging.Handler): # Inherit from logging.Handler
    def __init__(self):
        # run the regular Handler __init__
        logging.Handler.__init__(self)
        # Our custom argument
        self.mongo = MongoLogger()

    def setupCustomLogger(self, name, this_host):
        formatter = MyLogFormatter(fmt='%(asctime)s - %(levelname)s - %(module)s - %(message)s - %(host)s')

        handler = logging.StreamHandler()
        handler.setFormatter(formatter)

        logger = logging.getLogger(name)
        logger.setLevel(logging.DEBUG)
        logger.addHandler(handler)
        return logger

    def emit(self, record):
        # record.message is the log message
        self.mongo.log(record)


class MongoLogger(object):

'''Logs messages to a MongoDB fh_admin log collection.'''
def log(self, message):
    #@todo write log to DB
    print message
4

1 に答える 1

10

エラーは、何が問題なのかを正確に示しています。引数が多すぎるコンストラクターを呼び出しています。私の言いたいことを理解するために、ログ レコードが のデフォルトの実装で通常どのように構築されるかを見てみましょうmakeRecord

def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
    """
    A factory method which can be overridden in subclasses to create
    specialized LogRecords.
    """
    rv = LogRecord(name, level, fn, lno, msg, args, exc_info, func)
    if extra is not None:
        for key in extra:
            if (key in ["message", "asctime"]) or (key in rv.__dict__):
                raise KeyError("Attempt to overwrite %r in LogRecord" % key)
            rv.__dict__[key] = extra[key]
    return rv

makeRecord が、extra直接渡さないパラメータを受け取る方法に注意してLogRecordください。一方、それを に直接渡しているためLogRecord.__init__、エラーが発生しています。

ここから、2 つのオプションがあります。のより完全な実装を提供するか、より少ないコードで同じ目標を達成するのに役立つクラスをmakeRecord使用してみることができます。LoggerAdapter

次に例を示します。

# Common log info to be added to all logs reported with `log_adapter`
context = {'host': 'localhost'}

log = logging.getLogger('testing')
log.addHandler(logging.StreamHandler())
d = {'host': '192.168.0.1'}

log_adapter = logging.LoggerAdapter(log, context)
log_adapter.warning('Hi', d)

たとえば、何かがログに記録されるたびに「ホスト」の値を計算する必要がcontextある場合は、辞書のようなクラスのインスタンスを作成できます。そのようです:

class LogContext(object):

    def __getitem__(self, key):
        if key == 'host':
            return 'localhost'
        raise KeyError(key)

    def __iter__(self):
        return iter(['host'])

log_adapter = logging.LoggerAdapter(log, LogContext())
log_adapter.warning('Hi', d)

注意すべきことLoggingAdapterの 1 つは、便利なショートカット関数のすべてを通常の Logger クラスとして定義していないようです。warningそのため、上記の代わりにメソッドを呼び出しましたwarn

LoggingAdapterログへのコンテキストの追加と追加の詳細については、 python docsを参照してください。

注 - 、、、またはは問題/エラーに関連していないため、例にはMyLogHandler含めませんでした。MyLogFormatterMongoLogger

于 2012-06-30T04:11:45.097 に答える