モチベーション
できるだけ簡単な方法で、複数のクラスから同一ログファイルにログを出力したい。
実験
コードはこちら。
まずは互いに継承関係にない2つのクラスClass_A
とClass_B
を準備します。
>exam_logging
│ exam_logging_1.ipynb ←実験(その1)
│ exam_logging_2.ipynb ←実験(その2)
│
├─lib
│ │ cls_a.py ←Class_A
│ │
│ └─tmp
│ cls_b.py ←Class_B
│
└─logs
logger_1.log ←自動で作られる
logger_2.log ←自動で作られる
それぞれのクラスの中身は以下の通り。Class_A
のほうにのみlogging.basicConfig
でログファイルおよびログレベルの指定をしておきます。
import logging
class Class_A:
def __init__(self, filename):
logging.basicConfig(filename=filename, level=logging.DEBUG)
self.logger = logging.getLogger(__name__)
return
def get_hello(self):
self.logger.critical('\tHello, I\'m CRITICAL!')
self.logger.error('\tHello, I\'m ERROR!')
self.logger.warning('\tHello, I\'m WARNING!')
self.logger.info('\tHello, I\'m INFO!')
self.logger.debug('\tHello, I\'m DEBUG!')
return
import logging
class Class_B:
def __init__(self):
self.logger = logging.getLogger(__name__)
return
def get_hello(self):
self.logger.critical('\tHello, I\'m CRITICAL!')
self.logger.error('\tHello, I\'m ERROR!')
self.logger.warning('\tHello, I\'m WARNING!')
self.logger.info('\tHello, I\'m INFO!')
self.logger.debug('\tHello, I\'m DEBUG!')
return
(蛇足) 出力結果をきれいにしたくてログの先頭に\t
を入れてみたものの、思ったほどきれいじゃなかった。。
実験(その1)
exam_logging_1.ipynb を参照。
- はじめに
Class_A
のインスタンスを作ってget_hello
を呼び出し - 次に
Class_B
のインスタンスを作ってget_hello
を呼び出し
できあがったログファイルの中身を見ると
CRITICAL:lib.cls_a: Hello, I'm CRITICAL!
ERROR:lib.cls_a: Hello, I'm ERROR!
WARNING:lib.cls_a: Hello, I'm WARNING!
INFO:lib.cls_a: Hello, I'm INFO!
DEBUG:lib.cls_a: Hello, I'm DEBUG!
CRITICAL:lib.tmp.cls_b: Hello, I'm CRITICAL!
ERROR:lib.tmp.cls_b: Hello, I'm ERROR!
WARNING:lib.tmp.cls_b: Hello, I'm WARNING!
INFO:lib.tmp.cls_b: Hello, I'm INFO!
DEBUG:lib.tmp.cls_b: Hello, I'm DEBUG!
Class_B
ではログファイル出力先等を設定していないにもかかわらず、Class_A
で指定したログファイルにClass_B
のログが出力されています。
いわばlogging
はシングルトンのようなものでしょうか。
なので基本的には、部品となるクラスでは出力先の設定等を行わずに、ふつうにself.logger.debug()
等でログ出力。部品を使う側でlogging.basicConfig()
でログ出力先等の設定を行うような使い方ができるかと思います。(※)
実験(その2)
exam_logging_2.ipynb を参照。
- こんどは先に
Class_B
のインスタンスを作ってget_hello
を呼び出し - そのあとで
Class_A
のインスタンスを作ってget_hello
を呼び出し
その結果:
CRITICAL:lib.cls_a: Hello, I'm CRITICAL!
ERROR:lib.cls_a: Hello, I'm ERROR!
WARNING:lib.cls_a: Hello, I'm WARNING!
INFO:lib.cls_a: Hello, I'm INFO!
DEBUG:lib.cls_a: Hello, I'm DEBUG!
Class_B
のほうのログはファイル出力されていませんね。当然か。
で、標準出力のほうを見ると
Hello, I'm CRITICAL!
Hello, I'm ERROR!
Hello, I'm WARNING!
となっています。(デフォルトではログレベルがINFO
またはDEBUG
のログは出力されないようです)
さらに、
3 . ふたたびClass_B
のget_hello
を呼び出し
すると、ファイルの中身は
CRITICAL:lib.cls_a: Hello, I'm CRITICAL!
ERROR:lib.cls_a: Hello, I'm ERROR!
WARNING:lib.cls_a: Hello, I'm WARNING!
INFO:lib.cls_a: Hello, I'm INFO!
DEBUG:lib.cls_a: Hello, I'm DEBUG!
CRITICAL:lib.tmp.cls_b: Hello, I'm CRITICAL!
ERROR:lib.tmp.cls_b: Hello, I'm ERROR!
WARNING:lib.tmp.cls_b: Hello, I'm WARNING!
INFO:lib.tmp.cls_b: Hello, I'm INFO!
DEBUG:lib.tmp.cls_b: Hello, I'm DEBUG!
となり、ログ出力先だけでなくログレベルもClass_A
での設定が反映されました。
結果
- クラスが分かれていても、
logging
の設定は全体に反映される- ⇒(クラスが)離れていても、心(出力先)はひとつ!
- (ついでに)ログレベルのデフォルトは
WARNING
補足
(※)import logging
を使うことの是非については議論があります。たとえばこちら。