環境
- Python 3.6.6
- logging v0.5.1.2
- Windows 10
やりたいこと
Pythonのloggingを使って、コンソールとログファイルにログを出力したいです。
以下のファイルを生成しました。
ディレクトリ構成
$ ls
logger-main.py
fuga.py
logging.yaml
logging-main.py
import logging
import logging.config
import yaml
from fuga import Fuga
if __name__ == "__main__":
logging.config.dictConfig(yaml.load(open("logging.yaml").read()))
f = Fuga()
fuga.py
import logging
import yaml
logger = logging.getLogger(__name__)
class Fuga:
def __init__(self):
logger.debug("Fuga Constructor in debug")
logger.info("Fuga Constructor in info")
logging.yaml
version: 1
formatters:
customFormatter:
format: '%(asctime)s : %(levelname)s : %(module)s : %(message)s'
handlers:
fileRotatingHandler:
class: logging.handlers.TimedRotatingFileHandler
level: DEBUG
filename: logfile/logger.log
when: 'D'
formatter: customFormatter
consoleHandler:
class: logging.StreamHandler
level: DEBUG
formatter: customFormatter
loggers:
fuga:
level: DEBUG
handlers: [fileRotatingHandler, consoleHandler]
root:
level: INFO
handlers: [fileRotatingHandler, consoleHandler]
問題
$ python logging-sample.py
を実行すると、以下のように重複したログが、コンソールとログファイルに出力されました。
2019-03-16 16:45:02,746 : INFO : fuga : Fuga Constructor in info
2019-03-16 16:45:02,746 : INFO : fuga : Fuga Constructor in info
原因
logging.Logger.propagate
には以下のように書いてあります。
ハンドラを、あるロガー と その祖先のロガーに接続した場合、同一レコードが複数回発行される場合があります。一般的に、ハンドラを複数のロガーに接続する必要はありません。propagate 設定が True のままになっていれば、ロガーの階層において最上位にある適切なロガーにハンドラを接続するだけで、そのハンドラは全ての子孫ロガーが記録する全てのイベントを確認することができます。一般的なシナリオでは、ハンドラをルートロガーに対してのみ接続し、残りは propagate にすべて委ねます。
ルートロガーとfugaロガーの両方にハンドラを設定していることが原因でした。
なお、propagateはデフォルトTrueです。
解決方法
方法1:fugaロガーにハンドラを指定しない
logging.yaml
loggers:
fuga:
level: DEBUG
方法2:fugaロガーpropagate値をfalseにする
logging.yaml
loggers:
fuga:
level: DEBUG
handlers: [fileRotatingHandler, consoleHandler]
propagate: false