[Python] 複数モジュールのログを1つのファイルに出力するには?

Python logging
Python
スポンサーリンク

これまでに、以下の記事で logging によるログ出力方法について説明をしてきました。

いずれも、1つのモジュール内におけるログ出力の方法でした。
しかし、実際にアプリケーションを開発する上では、複数のモジュールとなります。
そこで今回は、複数のモジュールのログを1つのファイルに出力する方法について説明をします。

今回作成するアプリケーションのイメージ

今回作成するアプリケーションのイメージを以下に示します。

loggingSample.py(親モジュール) と sub_module.py(子モジュール) という2つのモジュールで構成し、それぞれのログは app.log に出力することとします。

作成するサンプルコードのイメージ

作成するサンプルコードのイメージ

メインモジュールのログ出力設定

メインモジュール(loggingSample.py)におけるログ出力設定のサンプルコードを以下に示します。

loggingSample.py

import logging
import sub_module

# ロガー(loggingSample)の作成
logger = logging.getLogger('loggingSample')
logger.setLevel(logging.DEBUG)
# ファイルハンドラーの作成とログレベルの設定
fh = logging.FileHandler('app.log')
fh.setLevel(logging.DEBUG)

# フォーマッターの作成
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)

# ハンドラーの追加
logger.addHandler(fh)

logger.info('sub_module の Sample インスタンスを生成')
sample = sub_module.Sample()

logger.info('sub_module の Sample クラスが持つ do_something の呼び出し')
sample.do_something()

logger.info('sub_module の some_function() の呼び出し')
sub_module.some_function()

1行目は、ログを出力するための logging モジュールのインポート、2行目はサブモジュールである sub_module のインポートです。

5行目は、loggingSample という名前でロガーを作成しています。この loggingSample という名前を基本として、他のモジュールでも使用します

6行目は、ログ出力レベルを DEBUG に設定しています。

8行目は、ファイルハンドラーを作成し、ログの出力先を app.log にしています。

9行目は、作成したファイルハンドラーのログ出力レベルを DEBUG に設定しています。

12行目は、出力するログのフォーマットを設定しています。ここでは、ログの出力日時、ログを出力したモジュールおよびクラス名、ログ出力レベル、メッセージ、が表示されるように書式を作成しています。フォーマットの詳細は「ログ出力フォーマットを設定するには?」を参照してください。

13行目は、作成したフォーマッターをファイルハンドラーに追加しています。

16行目は、作成したファイルハンドラーをロガーに追加しています。

18行目以降は、ログの出力と、サブモジュールの利用を行っています。

サブモジュールのログ出力設定

続いて、サブモジュール(sub_module.py)のサンプルコードを示します。

このモジュールは以下を持ちます

  • Sample というクラス
  • Sample クラスのコンストラクタ(クラスの初期化関数)
  • Sample クラスの do_something()
  • 関数 some_function()

sub_module.py

import logging

# ロガーの作成
module_logger = logging.getLogger('loggingSample.sub_module')
#module_logger = logging.getLogger('loggingSample').getChild('sub_module')

class Sample:
    def __init__(self):
        self.logger = logging.getLogger('loggingSample.sub_module.Sample')
        #self.logger = logging.getLogger('loggingSample').getChild('sub_module').getChild('Sample')
        self.logger.info('Sample クラスのインスタンスを生成しました')

    def do_something(self):
        self.logger.info('do_something が呼び出されました')

def some_function():
    module_logger.info('some_function が呼び出されました')

1行目は、logging モジュールのインポートです。サブモジュールでもログ出力をおこないますので、インポートが必要です。

4行目は、サブモジュール内で使用するロガーを作成しています。このとき、メインモジュールで作成した「loggingSample」というロガー名を基本にして、「sub_module」という名前を付けています。このように「メインモジュールのロガー名.サブモジュールのロガー名」という書式にすることによって、複数モジュールのログが、メインモジュールで作成したログの出力先にまとめられます。ここで作成した「loggingSample.subModule」は、sub_module.py 内で全体で使用可能なロガーとなります。

ちなみに「logging.getLogger(‘loggingSample.sub_module’)」は、5行目のように「logging.getLogger(‘loggingSample’).getChild(‘sub_module’)」とすることもできます。

7〜14行目は、Sample クラスの定義です。

8〜11行目は、Sampleクラスのコンストラクタです。

9行目で、Sample クラス内で使用する専用ロガーを作成しています。このとき、「loggingSample」の「sub_module」の「Sample」ロガーということを「loggingSample.sub_module.Sample」として、メインモジュールの孫ロガーとすることで、ログの出力先をメインモジュールで作成したロガーに結びつけることができます。

11行目は、作成した Sampleロガーを使用して、ログを出力しています。

13行目は Sample クラスに属する do_something 関数の定義で、14行目は関数が呼び出されたときに実行するログの出力です。

14行目は、some_function() という関数の定義です(Sampleクラスとは関係がありません)。この関数が呼び出されたときは、4行目で定義したロガーを使用してログ出力をしています。

各ロガーのイメージ

作成した各ロガーの親子関係のイメージを以下に示します。

作成したロガーのイメージ

作成したロガーのイメージ

実行結果の確認

実行時のログ出力結果例を以下に示します。

それぞれのログがどこのモジュールで出力されたのかがわかります。

app.log

2021-01-04 13:00:26,625 - loggingSample - INFO - sub_module の Sample インスタンスを生成
2021-01-04 13:00:26,626 - loggingSample.sub_module.Sample - INFO - Sample クラスのインスタンスを生成しました
2021-01-04 13:00:26,626 - loggingSample - INFO - sub_module の Sample クラスが持つ do_something の呼び出し
2021-01-04 13:00:26,626 - loggingSample.sub_module.Sample - INFO - do_something が呼び出されました
2021-01-04 13:00:26,626 - loggingSample - INFO - sub_module の some_function() の呼び出し
2021-01-04 13:00:26,626 - loggingSample.sub_module - INFO - some_function が呼び出されました

 

参考

Logging クックブック
著者, Vinay Sajip ,. このページは、過去に有用であるとされていた、logging に関連するいくつものレシピを含んでいます。チュートリアルやリファレンス情報へのリンクについては その他のリソース を参照してください。 複数の...

 

Please follow and like us:

コメント

タイトルとURLをコピーしました