(最終更新月:2023年9月)
✔以下のような方へ向けて書かれた記事となります
「Pythonでログを取る方法を知りたい」
「Pythonのloggingモジュールの使い方を学びたい」
「Pythonでのログの実践的な例が見たい」
✔当記事を通じてお伝えすること
- Pythonでのログ取得の基本
- loggingモジュールの書き方や応用
- Pythonを用いたログ取得の実例
当記事では、Pythonでのログ取得の基本から、loggingモジュールを使った応用的な使い方を具体的な例を交えながらわかりやすく解説しています。
最後までお付き合いいただき、Pythonでのログ取得をマスターしてください。
Pythonでログを取るための前提知識
当記事では、Pythonプログラミングにおけるログの重要性と、その取り方について詳しくお伝えします。
以下のテーマについて詳しく解説します。
- ログとは?
- プログラミングでのログの利点
- ログの重要性
ログとは?
ログとは、プログラムの実行過程で出力される情報のこと。
適切に取得・管理することでシステムの動作状況を把握したり、問題発生時の原因追求に役立てたりが可能です。
ログは文字情報として出力され、時間や出来事の詳細、重要度(ログレベル)などが記録されます。
プログラミングでのログの利点
プログラミングにおいて、ログを適切に取得・利用することはデバッグやトラブルシューティングにおいて非常に重要です。
エラー発生時の状況を詳細に把握できるので、問題の原因を早期に見つけられます。
ログを時間軸に沿って分析し、システムのパフォーマンス監視や、長期的なトレンド分析にも利用可能です。
Pythonプログラミングにおけるログの重要性
Pythonプログラミングにおいて、ログは以下のような用途で欠かせないツールのひとつです。
- バグの特定
- パフォーマンスの解析
- アプリケーションの動作モニタリング
Python標準ライブラリ「logging」とは
こちらでは、Pythonの標準ライブラリであるlogging
モジュールについてお伝えします。
ログを扱うために覚えておくべきモジュールです。
- loggingモジュールとは
- loggingモジュールの例
- loggingモジュールの使い方
loggingモジュールの説明
Pythonのlogging
モジュールは、プログラムの動作中にログメッセージを出力する、標準ライブラリの一部です。
このモジュールを使用すると、さまざまな重要度のログメッセージを出力できます。
以下がその特徴です。
- Logger
ログの出力を制御する主要なオブジェクト。アプリケーションやライブラリの異なる部分で異なるロガーを持てます。 - Handler
ログメッセージをどこに送るかを決定するオブジェクト。例えば、ログメッセージをコンソールに出力するためのStreamHandler
や、ログメッセージをファイルに書き込むためのFileHandler
などがあります。 - Formatter
ログメッセージのフォーマットを決定するオブジェクト。例えば、日付、ログの重要度、メッセージ本文などの情報をどのように表示するかを定義します。 - Log Record
ロガーが生成するログメッセージの情報を保持するオブジェクト。 - Log Level: ログの重要度を示すレベル。以下のような標準的なレベルがあります。
- DEBUG
- INFO
- WARNING
- ERROR
- CRITICAL
loggingモジュールの例
以下は、logging
モジュールを使用した基本的な例です。
import logging
# ログの設定
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
# ログの出力
logging.debug('デバッグメッセージ')
logging.info('情報メッセージ')
logging.warning('警告メッセージ')
logging.error('エラーメッセージ')
logging.critical('致命的なエラーメッセージ')
またログメッセージのフォーマットには、以下の情報が含まれています。
- タイムスタンプ
- ログレベル
- メッセージ本文
logging
モジュールは非常に柔軟で、多くの設定やカスタマイズが可能です。
公式ドキュメントや関連するリソースを参照することで、さらに詳しい情報や高度な使用方法を学べます。
loggingモジュールの使い方 (import方法)
logging
モジュールを使用するにはまず、以下のようにimport
します。
import logging
ログを出力するためには、以下のような関数を用いることが一般的です。
- logging.info()
- logging.warning()
- logging.error()
例えば、以下のように使用します。
logging.warning('This is a warning message')
上記のコードを実行すると、”WARNING:root:This is a warning message”というメッセージが出力されます。
ログレベルの設定
logging
モジュールでは、ログメッセージに重要度を示すログレベルを設定することが可能です。
ログレベルの詳細な設定方法とその役割について理科を深めましょう。
- ログレベルとは
- ログレベルの設定方法とデフォルト設定
- 独自のログレベルを追加する方法
ログレベルとは
logging
モジュールでは、以下の5つのログレベルが用意されています。
その種類と、目的は以下のとおりです。
- DEBUG: デバッグ情報。詳細な情報が必要な場合に出力します。
- INFO: 一般的な情報。システムの動作を追跡するのに役立ちます。
- WARNING: 何か問題が起こる可能性があるときに出力します。
- ERROR: 何か問題が起こったときに出力します。
- CRITICAL: 非常に深刻な問題が起きたときに出力します。
ログレベルの設定方法とデフォルト設定
ログレベルは、logging
モジュールのbasicConfig
関数を使って設定可能です。
ここで設定したログレベルが、以降のログ出力全体に適用されます。
以下が例です。
logging.basicConfig(level=logging.DEBUG)
logging.debug('This will get logged')
ログレベルをDEBUGに設定することで、DEBUGレベル以上(DEBUG, INFO, WARNING, ERROR, CRITICAL)の全てのログが出力されます。
なお、basicConfig
関数を呼び出さずにログ出力すると、デフォルトのログレベルはWARNINGです。
つまりデフォルトでは、WARNING、ERROR、CRITICALレベルのログのみが出力されます。
独自のログレベルを追加する方法
logging
モジュールでは、5つの基本的なログレベル以外にも、独自のログレベルを追加できます。
これはlogging
モジュールのaddLevelName
関数を使っておこなうものです。
ただし一般的には、5つの基本的なログレベルを使うことで十分な場合がほとんどです。
LoggerオブジェクトとHandlerオブジェクト
ログの出力設定をより細かく制御するために、logging
モジュールではLoggerオブジェクトとHandlerオブジェクトを提供しています。
それぞれの役割と利用方法について以下で詳しく解説します。
- Loggerオブジェクトの役割と利用法
- ハンドラオブジェクトの役割と設定方法
Loggerオブジェクトの役割と利用法
Loggerオブジェクトは、アプリケーションやライブラリのコンポーネントごとに個別のログ出力設定をおこなうためのものです。
特定のモジュールのログレベルを、別のモジュールとは独立に設定する場合に使用します。
Loggerオブジェクトは、logging
モジュールのgetLogger
関数で取得しましょう。
引数にはロガーの名前を指定しますが、通常はモジュール名を指定します。
logger = logging.getLogger(__name__)
logger.warning('This is a warning message')
getLogger
関数に`name`を指定して、Loggerオブジェクトを取得。
このロガーオブジェクトを使ってログメッセージを出力すると、その出力はこのLoggerオブジェクトの設定に従います。
Handlerオブジェクトの役割と設定方法
Handlerオブジェクトは、ログメッセージをどの出力先(例えば、コンソール、ファイル、メール等)にどのように出力するかを決定します。
複数のハンドラを設定することで、同じログメッセージを複数の出力先に送ることも可能です。
ハンドラオブジェクトの設定は、ロガーオブジェクトのaddHandler
メソッドを用いておこないます。
以下がその例です。
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
logger.addHandler(handler)
logger.warning('This is a warning message')
上記のコードでは、StreamHandler
を生成し、ロガーオブジェクトに追加しています。
StreamHandler
は、ログメッセージをコンソールに出力するハンドラです。
ログ出力先のカスタマイズ
ログの出力先を自由にカスタマイズする方法について解説します。
- 標準出力へのログ出力方法
- ファイルへのログ出力方法(追記モードと上書きモード)
- 両方の方法を組み合わせる方法
標準出力へのログ出力方法
先ほどのハンドラオブジェクトの設定の例では、StreamHandler
を使用してログメッセージを標準出力に出力しました。
これは一番基本的なログの出力方法であり、デバッグ時などによく使われます。
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
logger.addHandler(handler)
logger.warning('This is a warning message')
上記のコードを実行すると、「This is a warning message」というメッセージがコンソールに出力されます。
ファイルへのログ出力方法(追記モードと上書きモード)
ログメッセージをファイルに出力するには、FileHandler
を使用します。
FileHandler
は初期化時に出力先のファイル名を引数として取ります。
また、第二引数にはファイルの開き方を指定することができ、’a’を指定すると追記モード、’w’を指定すると上書きモードになります。
以下に例を示します。
logger = logging.getLogger(__name__)
handler = logging.FileHandler('my_log.log', 'a')
logger.addHandler(handler)
logger.warning('This is a warning message')
「This is a warning message」というメッセージがmy_log.logという名前のファイルに出力。
第二引数で’a’を指定しているため、同じコードを何度も実行しても、メッセージはファイルに追記されていきます。
‘w’を指定した場合は、コードを実行するたびにファイルが上書きされます。
両方の方法を組み合わせる方法
複数のハンドラを同時に設定することで、同じログメッセージを標準出力とファイルの両方に出力することも可能です。
以下に例を示します。
logger = logging.getLogger(__name__)
stream_handler = logging.StreamHandler()
file_handler = logging.FileHandler('my_log.log', 'a')
logger.addHandler(stream_handler)
logger.addHandler(file_handler)
logger.warning('This is a warning message')
上記のコードを実行すると、「This is a warning message」というメッセージがコンソールに出力されるとともに、my_log.logという名前のファイルにも出力されます。
ログ出力の設定やカスタマイズにより、さまざまな状況に対応できるでしょう。
ログフォーマットのカスタマイズ
この節では、ログフォーマットのカスタマイズ方法についてお伝えします。
- ログの見やすさについて
- ログフォーマットの要素
- ログフォーマットの設定方法
ログの見やすさについて
ログのフォーマットは、プログラムの動作を理解しやすくするための重要な要素です。
なぜならログが見やすくなければ、プログラムの動作を追跡するのが難しくなるからです。
読みやすさと解釈のしやすさを向上させるためにカスタマイズすることが推奨されます。
ログフォーマットの要素
ログフォーマットは一般的に、以下で構成されます。
- 日付
- 時間
- ログレベル
- メッセージ
- 発生源のファイル名
これらの要素は必要に応じて自由に組み合わせられ、それぞれが異なる情報を提供してプログラムの動作を理解しやすくします。
ログフォーマットの設定方法
Pythonのlogging
モジュールでは、ログフォーマットを設定するためのFormatter
クラスが提供されています。
Formatterクラスにより、自由な形式でログメッセージが作成可能。
以下に例を示します。
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.warning('This is a warning message')
出力は以下のとおりです。
2023-07-28 12:34:56,789 - __main__ - WARNING - This is a warning message
- %(asctime)s:出力時刻、
- %(name)s:ロガーの名前
- %(levelname)s:ログレベル
- %(message)s:ログメッセージ
自由に組み合わせられるので、多くの属性がlogging
モジュールによって提供されています。
スレッドセーフ性とLoggerAdapterオブジェクト
こちらでは、Pythonでのログ取り扱いにおけるスレッドセーフ性とLoggerAdapter
オブジェクトの利用法について解説します。
- スレッドセーフ性について
- LoggerAdapterオブジェクトの利用方法とメリット
スレッドセーフ性について
Pythonのlogging
モジュールは、マルチスレッド環境で安全に使用できます。
複数のスレッドが同時にログを出力する場合でも、それらのログメッセージは適切に処理され、予期せぬ問題を引き起こすことはありません。
プログラムのデバッグや問題の特定を容易にするために重要な特性です。
LoggerAdapterオブジェクトの利用方法とメリット
LoggerAdapter
オブジェクトは、ログメッセージに追加情報を付与するための便利なツールです。
各ログメッセージにコンテキスト情報を追加して出力することが可能となります。
以下に使用例を示します。
class ContextFilter(logging.Filter):
def filter(self, record):
record.ip = '123.456.789.012'
return True
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(ip)s - %(message)s')
handler.setFormatter(formatter)
logger.addFilter(ContextFilter())
logger.addHandler(handler)
logger.warning('This is a warning message')
このコードを実行すると、以下のような出力が得られます。
2023-07-28 12:34:56,789 - __main__ - WARNING - 123.456.789.012 - This is a warning message
ここで、%(ip)s
は新しく追加した情報(ここではIPアドレスを模擬)を表します。
このように、LoggerAdapter
を使うと各ログメッセージに独自の情報を付け加えられ、ネットワーク環境やマルチユーザー環境で役立つのです。
warningsモジュールとの連携
こちらでは、「warnings」モジュールについてお伝えし、それがPythonのlogging
モジュールとどのように連携するのかを説明します。
- warningsモジュールの紹介
- loggingとwarningsモジュールを組み合わせる方法
warningsモジュールの紹介
Pythonのwarnings
モジュールは、警告メッセージを出力するためのツールです。
警告はエラーではなく、通常のプログラムの実行を中止しないメッセージです。
以下のようなものを対象に用いられます。
- 何か問題が発生しそうな事象
- 非推奨の関数の使用や将来的に予期せぬ動作を引き起こす可能性のあるコード
loggingとwarningsモジュールを組み合わせる方法
warnings
モジュールとlogging
モジュールは組み合わせて使用できます。
警告をlogging
モジュール経由で出力することにより、以下のようなことが可能です。
- 警告メッセージの出力先を自由に指定
- フォーマットを自由に設定
- 警告メッセージを記録
以下に、warnings
モジュールの警告をlogging
モジュールを通じて出力する簡単な例を示します。
import warnings
import logging
# warningsのshowwarning()を上書き
def custom_showwarning(message, category, filename, lineno, file=None, line=None):
logging.warning('%s:%s: %s: %s' % (filename, lineno, category.__name__, message))
warnings.showwarning = custom_showwarning
# これは警告を生成します
warnings.warn('This is a warning message')
warnings.warn()
が呼び出されると、警告メッセージがlogging.warning()
を使って出力されるもの。
このようにして、logging
モジュールの全ての機能を利用して、警告をより効果的に制御することが可能となります。
実践編: Pythonプロジェクトでのloggingの活用
こちらでは、実際のPythonプロジェクトにおけるlogging
モジュールの活用について説明します。
特に、エラー処理や全体のログ設定に焦点を当てて見ていきましょう。
- サンプルコードの説明
- loggingモジュールを使ったエラー処理の実例
- プロジェクト全体で統一されたログ設定の方法
サンプルコードの説明
次のようなシンプルなPythonコードを考えてみましょう。
このコードは、データ処理を模擬したものです。
def process_data(data):
print("Processing data...")
# 何かしらの処理
# ...
print("Data processing completed.")
process_data("Sample data")
このコードは機能的には問題ありませんが、問題が発生したときに対処する方法がありません。
また、デバッグやトラブルシューティングに必要な情報が不足しています。
loggingモジュールを使ったエラー処理の実例
ここで、このコードをlogging
モジュールを使って改善してみましょう。
import logging
logging.basicConfig(level=logging.INFO)
def process_data(data):
logging.info("Processing data...")
try:
# 何かしらの処理
# ...
except Exception as e:
logging.error("Error occurred while processing data: %s", e)
raise
logging.info("Data processing completed.")
process_data("Sample data")
このコードは、処理中に何が起こっているかをログに記録し、処理中にエラーが発生した場合にはその情報もログに記録します。
これにより、エラーが発生した原因を調査しやすくなります。
プロジェクト全体で統一されたログ設定の方法
大規模なプロジェクトでは、すべてのモジュールで統一されたログ設定を使用することが重要です。
これを達成するひとつの方法は、専用の設定ファイルを作成し、プログラムの開始時にそれを読み込むこと。
以下に例を示します。
import logging.config
logging.config.fileConfig('logging.conf')
# これ以降、loggingは設定ファイルに基づいて動作します
まとめ
当記事では、Pythonでのログ取得についてお伝えしてきました。
- ログは、プログラムの実行中に何が起こったのかを記録し、エラーが発生したときの原因分析やパフォーマンスの調査に役立つ重要なツール
- Pythonの標準ライブラリに含まれる
logging
モジュールを使用することで、Pythonプログラムに簡単にログ機能を追加できる - ログレベルの設定、ログ出力先のカスタマイズ、ログフォーマットの変更など、詳細な設定も可能
当記事があなたのPythonでのログ取得に対する理解を深める一助となれば幸いです。