Python PR

【Python】loggingでログを記録する方法を解説

記事内に商品プロモーションを含む場合があります

この記事では、Pythonでログを記録する方法を解説します。

ログとは、ソフトウェア(アプリとか)を実行している際に起こったイベント(出来事)を記録したデータのことを言います。

ログを記録しておくことで不測の事態が発生した場合に原因を解明するための材料として使うことができてとても便利です。

それでは、ログを記録する方法を見てきましょう!

ログ(log)とは?

ログとは、コンピュータが付ける記録のことを言います。何かしらのアクションがあるたびに記録を付けることで、プログラム中で何が起こっているかを把握することができます。

いつどこから接続したのか確認するための「アクセスログ」や、コンピュータ上でエラーが発生したときに記録する「エラーログ」など様々な種類のログがあります。

ログは、人間が確認するものなので「いつ・誰が・何をしたか」などが記述されており、そのとき起こった出来事の詳細がわかるように記録するのが一般的です。

何かしら問題が起きた場合にログを確認することで原因を特定しやすくなります。

ログの基本

Pythonでログを記録するには、loggingモジュールを使います。loggingモジュールは、標準ライブラリなのでインポートするだけで使用可能です。

まずは、簡単にログを出力してみましょう!

import logging

# loggingクラスのインスタンス化
logger = logging.getLogger(__name__)
logger.warning('warning: ログです')

実行結果

warning: ログです

ログを扱うにはlogger(ロガー)を使います。

loggerは、loggerクラスから直接インスタンス化するのは禁止されており、必ずgetLogger()メソッドでインスタンス化する必要があります。

logger = logging.getLogger(__name__)

getLogger()メソッドの第一引数に文字列を指定することでloggerごとの名前を設定することができます。 __name__を指定することでモジュール名をロガー名に指定することができ、モジュールごとにログを記録する際に便利です。

また、同じ名前でロガーを生成した場合、常に同一のロガーオブジェクトを参照します。

そして最後にwarningメソッドでログを出力しています。

logger.warning('warning: ログです')
  • logger(ロガー)をgetLogger()メソッドで生成する
  • getLogger()メソッドの引数でロガーの名前を指定
  • 同じ名前のロガーは同一のオブジェクトを参照
  • 生成したloggerからログを出力

ログの出力先を設定する

ロガーにハンドラを設定することでログの出力先を変更することができます。

ハンドラが一つも設定されなかった場合、sys.stderrにログレベルWARNING以上のログを出力します。ログレベルについては後述します。

任意の場所にログを出力するには、StreamHandler()コンストラクタに任意のストリームを渡してハンドラを生成し、addHandler()メソッドでロガーに生成したハンドラを追加します。

試しに、「example.log」というファイルを作成してログを書き込んでみます。その際、open()関数のモードは'a'にし、ファイルが存在している場合は追記するようにしておきます。→ ファイルの読み書き

import logging

# ロガーのインスタンス化
logger = logging.getLogger(__name__)

with open('example.log', 'a') as f:
    # ファイルに出力するハンドラを生成
    sh = logging.StreamHandler(f)
    # ロガーにハンドラを追加
    logger.addHandler(sh)

    logger.warning('warning.')

このコードを実行すると以下のようなファイルが生成されました。

ファイルにログを出力するハンドラを生成したい場合は、FileHandler()クラスを使うとより簡単です。第一引数にファイル名、またはファイルのパスを指定するだけでOKです。

import logging

# ロガーのインスタンス化
logger = logging.getLogger(__name__)

# ファイルに出力するハンドラを生成
sh = logging.FileHandler('example.log')
# ロガーにハンドラを追加
logger.addHandler(sh)

logger.warning('warning.')

この他にも便利なハンドラが用意されているので気になる方はチェックしてください。

LinkLogging HOWTO --- 便利なハンドラ - Python ドキュメント

ちなみに、ハンドラは1つのロガーにいくつも設定することができます。

ログレベル

今まではwarning()メソッドを使ってログを出力していましたが、異なるログレベルを出力するメソッドを使うことでログの重要度を変えることができます。

ログレベルには、CRITICALERRORWARNINGINFODEBUGNOTSETがあり、 CRITICALが一番高く、NOTSETが一番低くなっています。

レベル 使うタイミング
DEBUG 問題を診断するときに使う
INFO 想定通りにいっているか確認
WARNING 想定外のことが起こりそうなときに使う
ERROR 重大な問題により、ある機能を実行できない
CRITICAL プログラム自体が実行を続けられない

それぞれのレベルのログを出力してみます。

# loggingモジュールのインポート
import logging

# ロガーのインスタンス化
logger = logging.getLogger(__name__)

logger.debug('debug.')
logger.info('info.')
logger.warning('warning.')
logger.error('error.')
logger.critical('critical.')

実行結果

warning.
error.
critical.

ロガーのデフォルトのログレベルはWARNINGに設定されているため、重要度がWARNING以上のログメッセージだけが出力されます。

ログレベルを設定するにはsetLevel()メソッドを使用します。試しにロガーのログレベルをinfoに設定して同様にログを出力してみます。

import logging
import sys

# ロガーのインスタンス化
logger = logging.getLogger(__name__)
# ハンドラの生成
sh = logging.StreamHandler(sys.stdout)
# ロガーにハンドラを追加
logger.addHandler(sh)
# ロガーのログレベルをinfoに設定
logger.setLevel(logging.INFO)

logger.debug('debug.')
logger.info('info.')
logger.warning('warning.')
logger.error('error.')
logger.critical('critical.')

実行結果

info.
warning.
error.
critical.

また、ハンドラにもログレベルを設定することができます。どちらにもログレベルが設定されている場合は、重要度が高い方が優先されます。

import logging
import sys

# ロガーのインスタンス化
logger = logging.getLogger(__name__)
# ハンドラの生成
sh = logging.StreamHandler(sys.stdout)
# ハンドラのログレベルを設定
sh.setLevel(logging.ERROR)
# ロガーにハンドラを追加
logger.addHandler(sh)
# ロガーのログレベルをinfoに設定
logger.setLevel(logging.INFO)

logger.debug('debug.')
logger.info('info.')
logger.warning('warning.')
logger.error('error.')
logger.critical('critical.')

実行結果

error.
critical.

ログによって重要度を変更することで確認するべきログを明確化できます。

フォーマッタを設定する

今までのコードでは、あまり意味のないログを出力していました。ログとして記録しておくべきなのは、「いつ、どこで、何が起きたか」などの詳しい情報です。

詳しい情報を出力するには、フォーマッタを生成してハンドラに追加します。すると、ログの情報をフォーマッタ通りに整形して出力させることができます。

import logging
import sys

# ロガーのインスタンス化
logger = logging.getLogger(__name__)
# ハンドラの生成
sh = logging.StreamHandler(sys.stdout)
# フォーマッタを生成
fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# ハンドラにフォーマッタをセット
sh.setFormatter(fmt)
# ロガーにハンドラを追加
logger.addHandler(sh)

logger.warning('warning.')

実行結果

2021-08-18 23:50:13,977 - __main__ - WARNING - warning.

出力できる属性とフォーマット方法については以下のリンクを参考にしてください。

LinkLogRecord 属性

まとめ

この記事では、Pythonの標準モジュールloggingを使ってログを記録する方法を解説しました。

何かしらのプログラムを作成した場合は、必ずログをとるようにしましょう!
どういうタイミングでログを記録すればいいの?って方は以下の記事が参考になります。

Linkログ設計指針 - Qiita

なんかゴチャゴチャしていて一見使いずらそうな感じのするログですが、絶対に必要な機能なのでちょこちょこ使って仕組みを忘れる前に慣れてしまいましょう!

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ