LoginSignup
1
0

More than 5 years have passed since last update.

logging ― (クラスが)離れていても、心(出力先)はひとつ!

Posted at

モチベーション

できるだけ簡単な方法で、複数のクラスから同一ログファイルにログを出力したい。

実験

コードはこちら

まずは互いに継承関係にない2つのクラスClass_AClass_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でログファイルおよびログレベルの指定をしておきます。

lib/cls_a.py
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
lib/tmp/cls_b.py
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 を参照。

  1. はじめにClass_Aのインスタンスを作ってget_helloを呼び出し
  2. 次にClass_Bのインスタンスを作ってget_helloを呼び出し

できあがったログファイルの中身を見ると

logger_1.log
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 を参照。

  1. こんどは先にClass_Bのインスタンスを作ってget_helloを呼び出し
  2. そのあとでClass_Aのインスタンスを作ってget_helloを呼び出し

その結果:

logger_2.log
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_Bget_helloを呼び出し

すると、ファイルの中身は

logger_2.log
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を使うことの是非については議論があります。たとえばこちら

1
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0