ログを出力する方法

logging モジュールを使うと、 ログを簡単に出力できるようになります。

ログファイルはソフトウェアの実行記録、不具合の調査など、様々な状況で利用できます。

特に不具合の調査などは、いつ必要になるかわからないので、通常実行時はログファイルを出力せずとも、 必要な時に実行オプションでログがとれるようにしてあると便利です。

「災害は忘れた頃にやってくる」との言葉通り、実装の詳細を忘れたころに、昔々に開発したプログラムの動作不具合で調査が発生することはよくあることです。

OS 等の環境のアップグレード等で不具合が出てきたりすることもあるので、 数年後に問題が出るのはある程度やむを得ないことでもあったりしますし、さらに数年も経てば担当者も代わり、 他の人がデバッグすることになる場合もあります。

このため、開発時に要所要所にログ出力機構を仕込んでおくのは大切です。

さて、logging モジュールには debuginfowarningerrorerror などの関数が用意されており、それぞれのレベル・重要度のログを出力できます。

レベルは次のように分類されています。

  • DEBUG:デバッグ用のログ。もっとも詳細なログ。
  • INFO:正常動作を含む情報ログ。
  • WARNING:警告ログ。エラーで処理を終了することはなくとも、問題がありそうな場合。
  • ERROR:エラーログ。正常動作しているけどエラーが発生する場合。
  • CRITICAL:クリティカル。データ破損、プログラムの停止等。

上から下に向かって、重要度が高まります。どのレベルとして、何を出力するかは開発者次第です。上記のコメントは目安というか参考にしてください。

例えば設定で「ログレベルを logging.WARNING に設定してログ出力をする」 とすれば、 WARNING、ERROR、CRITICAL のレベルのログのみが出力されます。

ログレベルはプログラムでは basicConfig で設定できます。

basicConfig はルートロガー (root logger) にストリームハンドラが設定されていない時に、ストリームハンドラを設定するために使われます。 既にハンドラが設定されていたら何もしません。つまり、プログラム内で basicConfig の一回目の呼び出しのみが有効です。

ではサンプルコードを実行してみましょう。次のコードは各種レベルのログを出力を試みますが、レベルは WARNING にしています。

import logging

logging.basicConfig(level=logging.WARNING)
logging.debug('1. This is debug.')
logging.info('2. This is info.')
logging.warning('3. This is warning.')
logging.error('4. This is error.')
logging.critical('5. This is critical')

これを実行した結果は次の通りです。basicConfig にてログレベルを WARNING に設定したので、 WARNING 以上のレベルのログが出力されいます。

さらに次の例では典型的なログファイルとして、ログメッセージの他、ログの出力時刻、ファイル名、行番号などを、 ファイルに出力します。

import logging
from _stat import filemode
MYFORMAT='[%(asctime)s]%(filename)s(%(lineno)d): %(message)s'
logging.basicConfig(
    filename='/home/keisukeo/test.log',
    filemode='w', # Default is 'a'
    format=MYFORMAT, 
    datefmt='%Y-%m-%d %H:%M:%S', 
    level=logging.WARNING)
logging.debug('1. This is debug.')
logging.info('2. This is info.')
logging.warning('3. This is warning.')
logging.error('4. This is error.')
logging.critical('5. This is critical.')

baseConfig のオプションで filename でファイル名を渡すと、 そのファイルにログを出力します。

ログファイルを開くモード filemode で指定します。 デフォルトでは a です。既にログファイルが存在する場合は、 そのファイルに追加 (アペンド) します。ただし、ファイルが存在しない場合はログが出力されないことになるので要注意です。

ファイルがなければ作成するには filemodew で開きますが、 この場合既に存在するファイルは消去されます。

また時刻のフォーマットは datefmt オプションで指定できます。

ログの設定ファイルを利用する場合

さて、ログ出力の設定をソースコード内に記述せずに、ログの設定ファイルを利用する方法について説明します。

上で basicConfig を使ってその場でログを設定する方法を説明しましたが、実際のプログラムでは次のようにログの設定ファイルを別個の設定ファイルに記述しておき、 必要に応じてレベルに応じたログを出力できるようにしておくと便利です。

上述の内容と同等のログを出力する例を次に示します。

次の内容を logging.conf として保存します。ファイル名は何でも構いません。

[loggers]
keys=root

[handlers]
keys=consoleHandler,fileHandler

[formatters]
keys=f1

[logger_root]
level=WARNING
handlers=fileHandler,consoleHandler

[handler_consoleHandler]
class=StreamHandler
formatter=f1
args=(sys.stdout,)

[handler_fileHandler]
class=FileHandler
formatter=f1
args=('/home/keisukeo/test.log',)

[formatter_f1]
format=[%(asctime)s]%(filename)s(%(lineno)d): %(message)s
datefmt=%Y-%m-%d %H:%M:%S

次に設定ファイルを読み込むように変更します。

import logging
import logging.config

logging.config.fileConfig('logging.conf')
logger = logging.getLogger('root')

logger.debug('1. This is debug.')
logger.info('2. This is info.')
logger.warning('3. This is warning.')
logger.error('4. This is error.')
logger.critical('5. This is critical.')

上記の設定ファイルでは標準出力とファイル両方にログを出力しています。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Python 入門