【Python】ログファイルを残してみよう!

Pythonロゴ

Pythonにはシステム動作の履歴を残すロギング機能を扱うモジュールが用意されています。
今回は logging モジュールを使用してログファイルの出力を試してみます。

ログとは?

ログファイルはシステムが動作した時にどのような動きをしたか記録する物になります。出力は画面出力・ファイル出力・メール送信など方法があります。
イメージとして人間が付ける日記のような物で、重要な箇所のみ記録に残すことができます。

基本操作

ログの画面出力

画面上にログ内容が表示されます。
コマンド画面によっては赤字でログは表示されます。

import logging

logging.error('errorメッセージ')

# 結果
# ERROR:root:errorメッセージ

ログのファイル出力

ログの表示内容をファイルに出力します。
ファイル出力時は画面表示はされません。

import logging

logging.basicConfig(filename='sample/test.log', level=logging.DEBUG)
logging.error('errorメッセージ')
ERROR:root:errorメッセージ

ログの出力レベルの変更

ログファイルには「error」以外に「warning」や「info」など重大度別でレベルが設定されています。出力するレベル設定によって重大度が低い情報は表示されないようになります。

import logging

logging.critical('criticalメッセージ')
logging.error('errorメッセージ')
logging.warning('warningメッセージ')
logging.info('infoメッセージ') # 表示されない
logging.debug('debugメッセージ') # 表示されない

# 結果
# CRITICAL:root:criticalメッセージ
# ERROR:root:errorメッセージ
# WARNING:root:warningメッセージ

ログの出力レベルを設定する事で表示されないログも出力されます。

import logging

logging.basicConfig(level=logging.DEBUG)
logging.critical('criticalメッセージ')
logging.error('errorメッセージ')
logging.warning('warningメッセージ')
logging.info('infoメッセージ')
logging.debug('debugメッセージ')

# 結果
# CRITICAL:root:criticalメッセージ
# ERROR:root:errorメッセージ
# WARNING:root:warningメッセージ
# INFO:root:infoメッセージ
# DEBUG:root:debugメッセージ

ログのレベルについて

Pythonドキュメントを確認するとログレベルは5段階に分かれており利用用途は下記のようになっています。詳細はPythonドキュメントを確認下さい。

重大度レベル名称用途
5 (高い)CRITICALプログラム自体が実行を続けられないことを表す、重大なエラー。
4ERRORより重大な問題により、ソフトウェアがある機能を実行できないこと。
3WARNING想定外のことが起こった、または問題が近く起こりそうである (例えば、'disk space low') ことの表示。
2INFO想定された通りのことが起こったことの確認。
1 (低い)DEBUGおもに問題を診断するときにのみ関心があるような、詳細な情報。
参考 Logging HOWTOPythonドキュメント

フォーマッタ

ロギング機能にはメッセージ内容の順番やテキストを変更できる「フォーマッタ」機能がついています。機能を利用することで独自ルールのログメッセージを出力する事ができます。

メッセージの内容変更

baseConfig に format のパラメータを渡すことで指定のメッセージ内容で出力されるようになります。サンプルでは生成時刻 %(asctime)s を入れるフォーマット文字列を設定しています。

import logging

formatter = '%(asctime)s:%(message)s'
logging.basicConfig(format=formatter)
logging.error('errorメッセージ')

# 結果
# 2020-02-28 14:52:00,382:errorメッセージ

フォーマット文字列には生成時刻以外のも複数種類があります。
下記Pythonドキュメントでご確認下さい。

参考 フォーマット文字列Pythonドキュメント

ロガー

複数人でシステム開発をする場合、ログファイルの運用ルールは開発部分によって変わるケースがあります。
例えばシステムでは warningレベルまで残すルールが設定されている中で、
モジュール開発時に一時 debugレベルまで残す必要がある場合、ルール変更をすると全ログのルールが変わってしまいます。

ロガーは上記の問題を解決する手段で、必要箇所だけ独自のルールを設定することができます。一部モジュールだけdebugレベルまで残すなどのルールが設定できます。

ベースのログ設定を引継独自ログレベルを出力

getLoggerを使うことで独自ルールが設定されたログ出力ができるようになります。
下記例はベースはwarningレベルまで残すルールですが、ロガーを使用してdebugレベルまで残すようにしています。また (__name__) を設定する事でログの出力されているファイルを特定できます。

import logging

# ベースのログ設定
logging.basicConfig(level=logging.WARNING)

# 独自のログ設定
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.debug('debugメッセージ')

# 結果
# DEBUG:__main__:debugメッセージ

独自のファイルにログ出力

FileHandlerを使用することで個別のログファイルに内容を出力することができます。下記例は sample/test2.log に個別で内容を出力するようにしています。

import logging

# ベースのログ設定
logging.basicConfig(filename='sample/test.log', level=logging.WARNING)

# 独自のログ設定
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

log_file = logging.FileHandler('sample/test2.log')
logger.addHandler(log_file)

logger.debug('debugメッセージ')
debugメッセージ

フィルタ

ログファイルに情報を残す場合に、パスワードやAPIのトークンキーなどセキュリティを考えて残すとまずい情報があります。
ログ保存時に残さないように開発できれば問題無いのですが、万が一入ってしまう場合を考慮してログに「フィルタ」を設定する事でリスクを軽減する事ができます。

指定文字が存在する場合、ログ出力しない

addFilterを使用することで独自ルールのフィルタを設定します。フィルタは事前にクラスを作ってルールを設定する必要があります。
下記例は token という文字が含まれるログを出力しないようにしています。

import logging

# tokenフィルタ用のクラス作成
class NoTokenLogFilter(logging.Filter):
    def filter(self, record):
        message = record.getMessage()
        return 'token' not in message

logger = logging.getLogger(__name__)

# フィルタ設定
logger.addFilter(NoTokenLogFilter())

logger.error('errorメッセージ ')
logger.error('errorメッセージ token=byuik2dawdaw')

# 出力
# errorメッセージ 
# ※token が入ったログは出力されず

サンプルプログラム

こちらの記事で作成したプログラムはGitHub環境にアップしております。
下記からダウンロードいただけます。

参考 log.py スクリプトGitHub python-beginner