Python標準ライブラリloggingについて

皆さま、こんにちは。
グローバルウェイ、プラットフォーム事業部のTです。
今回はPythonの標準ライブラリであるloggingについて、基本的な使い方と注意点を説明します。
はじめに
oggingとは、Pythonの標準ライブラリでログ出力を管理するために使用されます。公式には以下のように記述されています。
このモジュールは、アプリケーションやライブラリのための柔軟なエラーログ記録 (logging) システムを実装するための関数やクラスを定義しています。
標準ライブラリモジュールとしてログ記録 API が提供される利点は、すべての Python
モジュールがログ記録に参加できることであり、これによってあなたが書くアプリケーションのログにサードパーティーのモジュールが出力するメッセージを含ませることができます。
※https://docs.python.org/ja/3/library/logging.html
実運用でloggingが使用されている理由は、以下のメリットを享受するためで
print()と比べ保守性や拡張性が高く、運用や開発での負荷を軽減できます。
- 環境ごとのログレベルの制御が可能
- 出力形式の一貫性や出力先の柔軟性も高い
- 拡張性が高く、AWS CloudWatchやGCP Cloud Loggingへの連携が容易
基本的な使い方
次に基本的な使い方をサンプルコードと共に紹介します。
以下、myapp.pyを実行することでmyapp.logにログが出力されます。
# myapp.py
import logging
import mylib
logger = logging.getLogger('myapp')
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler('myapp.log')
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
handler.setLevel(logging.DEBUG)
logger.addHandler(handler)
def main():
logger.info('Started !')
logger.debug('Debug message !')
mylib.do_something()
logger.info('Finished !')
if __name__ == '__main__':
main()
# mylib.py
import logging
logger = logging.getLogger('myapp')
def do_something():
logger.info('Doing something')
loggerの設定について、1つずつ解説します。
logger = logging.getLogger('myapp')
ロガーと呼ばれるインターフェースを準備します。
同じ名前でgetLogger()を呼び出すことによって、常に同じロガーを参照できるため、
myapp.pyに記載したロガーの設定がmylib.pyで使用するロガーにも反映されます。
logger.setLevel(logging.DEBUG)
ロガーのログレベルの設定です。
ログレベルは重要度の低い順にDEBUG, INFO, WARNING, ERROR, CRITICALとなります。
今回はDEBUGを設定しているため、DEBUG以上のログが出力されます。
handler = logging.FileHandler('myapp.log')
ハンドラーの準備です。 ハンドラーとはログの送信先を制御するものです。
主なハンドラーには、コンソールに出力する「StreamHandler」と、ファイルに出力する「FileHandler」があります。
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
出力するログのフォーマットをハンドラーに設定します。
今回は「出力日時 - ロガー名 - ログレベル - ログメッセージ」のような形式で出力されます。
その他の属性については、以下の公式ドキュメントを確認してください。
※https://docs.python.org/ja/3/library/logging.html#logging.Formatter
handler.setLevel(logging.DEBUG)
ハンドラーのログレベルの設定です。
ロガーには複数のハンドラーを設定できるため、ハンドラーごとのログレベルの設定が必要です。
logger.addHandler(handler)
最後にロガーにハンドラーを追加して、ロガーの設定は完了です。
注意点
前の章でloggingの設定について説明しましたが、いくつか注意点があります。
まず、loggingから直接info()やwarning()などを使用しないことです。
これらの関数は、ルートロガーと呼ばれる最上位のロガーを使用してしまうため、
意図していない場所へのログの出力や、設定の衝突を招く可能性があります。
実際に先ほどのサンプルコードにlogging.info()とlogging.warning()を追加して
実行した場合の出力は、次の通りです。
# myapp.py
def main():
logger.info('Started !')
logger.debug('Debug message !')
logging.info('Info message !')
logging.warning('Warning message !')
mylib.do_something()
logger.info('Finished !')
# myapp.log
2025-12-26 04:27:37,829 - myapp - INFO - Started !
2025-12-26 04:27:37,830 - myapp - DEBUG - Debug message !
2025-12-26 04:27:37,830 - myapp - INFO - Doing something
2025-12-26 04:27:37,831 - myapp - INFO - Finished !
# 出力(コンソール)
WARNING:root:Warning message !
INFO:myapp:Doing something
INFO:myapp:Finished !
infoに記載したログは出力されず、warningの内容のみがコンソールに表示されています。さらに、これ以降のログも本来意図していない形でコンソールに出力されてしまっています。
これは、logging.warning()によってルートロガーが自動的に初期化され、
ルートロガーにハンドラーが意図せず設定されてしまったためです。
logging モジュールは階層構造を持っており、ルートロガーの設定は子ロガー(今回場合のは myapp)にも伝播します。そのため、ルートロガーを直接操作すると、アプリ全体のログ挙動に影響を及ぼします。
logging モジュールが階層構造を持っている点には注意が必要です。
以下のように basicConfig() を使用すると、ルートロガーの設定が変更されてしまいます。
その結果、他のモジュール( requests など)が内部で使用している logging にも影響を与え、意図しないログ出力が発生する可能性があります。
# test.py
import logging
import requests
logging.basicConfig(level=logging.DEBUG)
def main():
logging.debug('start')
requests.get('https://www.globalway.co.jp/')
logging.debug('finish')
if __name__ == '__main__':
main()
# myapp.log
DEBUG:__main__:Started
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): www.globalway.co.jp:443
DEBUG:urllib3.connectionpool:https://www.globalway.co.jp:443 "GET / HTTP/1.1" 200 None
DEBUG:__main__:Finished
(おまけ)階層構造を確認できるlogging_treeについて
階層構造をツリー形式で視覚的に確認できる便利なモジュールとして、logging_treeがあります。 pip install logging_tree でインストールでき、logging_tree.printout() を実行することで、現在のロガー階層構造を表示できます。 以下はサンプルコードで試した結果です。
ロガーやハンドラーの関係を直感的に把握できるため、構造の理解が進みます。
<--""
Level WARNING
|
o<--"myapp"
Level DEBUG
Handler File '/app/main/myapp.log'
Level DEBUG
Formatter fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s' datefmt=None
おわりに
今回は、 Python の標準ライブラリである logging について、基本的な使い方と注意点を解説しました。
Python公式には基本チュートリアル(https://docs.python.org/ja/3/howto/logging.html#basic-logging-tutorial)もあわせてご覧ください。
最後までお読みいただき、ありがとうございました。

