27

次のコードがあります。

import logging
class A(object):
    def __init__(self):
        self._l = self._get_logger()

    def _get_logger(self):
        loglevel = logging.INFO
        l = logging.getLogger(__name__)
        l.setLevel(logging.INFO)
        h = logging.StreamHandler()
        f = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
        h.setFormatter(f)
        l.addHandler(h)
        l.setLevel(loglevel)
        return l  

    def p(self, msg):
        self._l.info(msg)

for msg in ["hey", "there"]:
    a = A()
    a.p(msg)

私が得る出力は次のとおりです。

2013-07-19 17:42:02,657 INFO hey
2013-07-19 17:42:02,657 INFO there
2013-07-19 17:42:02,657 INFO there

「そこに」が2回印刷されるのはなぜですか? 同様に、ループ内にクラス A の別のオブジェクトを追加してメッセージを出力すると、3 回出力されます。

ドキュメントによると、ロガーの名前が一致する場合、logging.getLogger() は常にロガーの同じインスタンスを返します。この場合、名前は一致します。同じロガーインスタンスを返すべきではありませんか? 事実である場合、メッセージが複数回出力されるのはなぜですか?

4

4 に答える 4

32

logger は 1 回作成されますが、複数のハンドラーが作成されます。

一度作成しますA

a = A()
for msg in ["hey", "there"]:
    a.p(msg)

または、次のように変更_get_loggerします。

def _get_logger(self):
    loglevel = logging.INFO
    l = logging.getLogger(__name__)
    if not getattr(l, 'handler_set', None):
        l.setLevel(loglevel)
        h = logging.StreamHandler()
        f = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
        h.setFormatter(f)
        l.addHandler(h)
        l.setLevel(loglevel)
        l.handler_set = True
    return l  

アップデート

Python 3.2 以降、 を使用logging.Logger.hasHandlersして、このロガーにハンドラーが構成されているかどうかを確認できます。(ありがとう@toom)

def _get_logger(self):
    loglevel = logging.INFO
    l = logging.getLogger(__name__)
    if not l.hasHandlers():
        ...
    return l
于 2013-07-19T12:20:51.007 に答える