【Python】yaml形式の設定ファイルを読み込んでlogging !!【入門編】

python

【Python】yaml形式の設定ファイルを読み込んでlogging【入門編】

はじめに

アプリやツールを作っていると動作状況やエラーの確認の為にログを残したくなることはありませんか?

Pythonでは簡単にログを残すことができます。ちなみに、ログを残すことをloggingと言います。

今回紹介するのは設定ファイルを読み込んでloggingを行う方法です。色々試してみましたが、これが一番シンプルでおすすめです。

設定ファイルの書き方

設定ファイルはyaml形式で記述します。yamlというのはデータ構造を表現するための書き方の一つです。
設定ファイルには、どこにログを残すか、どんなフォーマットにするか、などを書いていきます。それでは、早速書いていきましょう !!

config.yaml

version: 1
formatters:
  testFormatter:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    datefmt: '%Y/%m/%d %I:%M:%S'
handlers:
  file:
    class: logging.handlers.RotatingFileHandler
    level: INFO
    formatter: testFormatter
    filename: test.log
    maxBytes: 1000
    backupCount: 1
loggers:
  testLogger:
    level: INFO
    handlers: [file]
    propagate: no
root:
  level: INFO
  handlers: []

最小限の設定ですが、ほとんどの場合はこれで十分だと思います。
それぞれの項目について少し説明したいと思います。

version

設定ファイルの書き方を決めるバージョン情報で、2019/08/03 時点では"1"しかないみたいです。
この項目は必ず記述していなければいけません。

formatters

これはログのフォーマットを設定する項目です。formatterはいくつでも作成でき、formatter名をつけることで、識別できます。上の例ではformatter名を"testFormatter"にしています。
formatではログ出力の形式、datefmtでは日付の形式を指定することができます。

handlers

ハンドラの設定で、どこにログを出力するかなどを記述します。この場合は、"test.log"という名前のファイルに出力し、ファイルサイズが1000byte以上になると自動でバックアップをとって新しいログファイルに書き込んでくれます。バックアップファイルの最大数は1つに設定しています。formatterには上で記述したものを指定します。levelについては後で説明するので、ここでは気にしないでくださいね。僕はhandlersの設定が一番難しいと思います。

loggers

ロガーの設定で、ここで作成したロガーを指定して、プログラム上でログを残していきます。handlersには上で記述したhandlerを指定します。propagateは伝播という意味ですが、とりあえずnoで問題ないです。

root

rootロガーの設定を行います。上のロガーの設定でpropagateをnoにしているため、今回はあまり関係ありません。でも必ず書いておかないといけないみたいです。

以上で、設定ファイルの記述は終わりです。ここまで来たらあともう少しです。

yamlファイルを読み込む

まずは、yaml形式のファイルを扱うため、pipでPyYAMLをインストールします。

pip3 install PyYAML

インストールできたら、実際にyamlファイルを読み込んでみましょう。

import yaml
read_data = open("config.yaml").read()  # yamlファイルを読み込み
yaml_data = yaml.safe_load(read_data)  # yaml形式を変換

ここでやっっていることは、まず"config.yaml"というyamlファイルを文字列として読み込んでいます。そしてyaml.safe_loadに渡して、yaml形式の文字列から辞書型のデータに変換しています。これでloggingに設定値を渡す準備ができました。

loggingにyaml_dataをしてロガーを取得する

loggingに設定値を渡すにはconfig.dictConfigにyamlデータを渡してあげるだけです。ロガーの取得はgetLoggerで行います。設定ファイルで作ったロガーの名前を渡します。

from logging import config, getLogger
config.dictConfig(yaml_data)
logger = getLogger('testLogger')

これであとはログを残したい場所でloggerを使うだけです。

loggingを行う方法

早速loggerを使ってみましょう。使い方は簡単で、ログを出力したい場所で用途に合わせて以下のメソッドを呼び出します。

logger.debug('message')  # 普段は表示しないけど、動作確認のときだけ表示したい
logger.info('message')  # 通常の動作ログ
logger.warning('message')  # 動作継続可能だが問題となる場合
logger.error('message')  # エラー発生時
logger.exception('message')  # 例外発生時
logger.critical('message')  # プログラムが続行できない致命的なエラー

errorとexceptionは似ていますが、errorはメッセージを表示するだけなのに対して、exceptionはスタックトレースも表示します。単にエラーメッセージを表示したいときはerrorを、例外処理のときはexceptionを使うと良さそうですね。

設定ファイルのときに説明を飛ばしましたが、ログにはレベルというものがあります。
上から順にログレベルが高くなっていて、例えば設定ファイルでlevelをINFOにするとそれより下のレベルのDEBUGが出力されなくなります。逆にlevelをDEBUGにするとすべて出力されるようになります。このあたりはデバッグ時と通常使用で使い分けてください。

試しに動かしてみる

ここまでのまとめとして実際に動かしてみましょう。設定ファイルはさっき作成したyaml.configを使います。コードは"test.py"という名前で作成しました。ちなみに設定ファイルをloggingに渡すところはまとめて一行で書いています。

test.py

import yaml
from logging import config, getLogger
def main():
    config.dictConfig(yaml.safe_load(open('config.yaml').read()))
    logger = getLogger('testLogger')
    logger.debug('debug')
    logger.info('info')
    logger.warning('warning')
    logger.error('error')
    try:
        open('')
    except Exception as exception:
        logger.exception(exception)
    logger.critical('critical')
if __name__ == '__main__':
    main()

出力結果はこんな感じです。コンソールとtest.logに出力されます。

2019/07/01 16:13:21 - testLogger - DEBUG - debug
2019/07/01 16:13:21 - testLogger - INFO - info
2019/07/01 16:13:21 - testLogger - WARNING - warning
2019/07/01 16:13:21 - testLogger - ERROR - error
2019/07/01 16:13:21 - testLogger - ERROR - [Errno 2] No such file or directory: ''
Traceback (most recent call last):
  File "/test.py", line 14, in main
    open('')
FileNotFoundError: [Errno 2] No such file or directory: ''
2019/07/01 16:13:21 - testLogger - CRITICAL - critical

まとめ

いかがだったでしょうか。
loggingは調べれば調べるほど奥が深そうですが、今回の内容だけで基本的なログ出力はできると思います。

ログを残すという作業は、地味で後回しにしがちですが、後で必ず役に立つと思うので、ぜひ導入してみてください^^

参考

公式ドキュメント
https://docs.python.org/ja/3/library/logging.html

コメント

タイトルとURLをコピーしました