何もhandlerが設定されていないのにlogが出力される
logの出力を止めるため、継承しているすべてのLogger
のHandler
を削除した。にもかかわらず、ログが表示されてしまった。
解決するまでかなり時間がかかったのでメモ。
Sponsored by Google AdSense
問題の再現
import sys
from logging import (
NullHandler,
StreamHandler,
lastResort,
getLogger,
INFO,
CRITICAL,
)
print(sys.version)
3.11.6 | packaged by conda-forge | (main, Oct 3 2023, 10:37:07) [Clang 15.0.7 ]
# loggerの生成
logger = getLogger(__name__)
logger
<Logger __main__ (WARNING)>
Handler
は持っていない。
logger.hasHandlers()
False
親ロガー (root logger) もHandler
は持っていない。
root_logger = logger.parent
print(f"{root_logger=}")
root_logger.hasHandlers()
root_logger=<RootLogger root (WARNING)>
False
root loggerより上位のロガーは存在しない。
print(root_logger.parent)
None
Handlerがないので何も表示されないはず、、と思ったがwarning以上のものが表示されてしまう。
def log_all_level() -> None:
logger.debug("debug")
logger.info("info")
logger.warning("warning")
logger.error("error")
logger.critical("critical")
log_all_level()
warning
error
critical
もちろん親にもHandler
がないので、propagate=False
にして伝搬をオフにしても結果は変わらない。
logger.propagate = False
log_all_level()
warning
error
critical
もちろんlogger
のlevel
をCRITICAL
より高くしてしまえば表示されない。しかし本質的な解決ではない。
# CRITICALより高いレベルしか表示できないように設定する
logger.setLevel(CRITICAL + 1)
log_all_level()
手動で高いレベルを設定してしまえば表示できてしまう。
logger.log(1000, "level1000")
level1000
逆にレベルを引き下げてもWARNING
以上しか表示されない。
logger.setLevel(INFO)
log_all_level()
warning
error
critical
なぜ表示されるのか
1つもhandlerが設定されていないとき、logging.lastResort
というHandler
にわたされる仕様になっているから。
このロガー (および Logger.propagate 属性を考慮した上で実効的にイベントが伝播する祖先のロガー) にハンドラが接続されていない場合、メッセージは lastResort に設定されたハンドラーに送られます。
lastResort
<_StderrHandler stderr (WARNING)>
isinstance(lastResort, StreamHandler)
True
解決策
「何も表示しない」というHandler
、NullHandler
を設定する。
logger.addHandler(NullHandler())
log_all_level()