これまでに、以下の記事で 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 が呼び出されました
参考
コメント