[Python] ログのファイル出力とログローテーション

Python logging
Python
スポンサーリンク

前回の記事では、Python におけるログ出力の基本について説明をしました。

今回は、より実用的に使えるよう、ログをファイル出力する方法について説明をします。

スポンサーリンク

環境

Python 3.9.1

VSCode1.52.1

スポンサーリンク

ログファイル出力の基本

前回の記事で、ログの出力レベルを設定するために basicConfig メソッドを使用しましたが、ログをファイルに出力する場合も、basicConfig メソッドで設定をします。

basicConfig の引数に、「filename=”ログ出力ファイルパス”」を記載することで、ファイルにログが出力されるようになります。

※ basicConfig でログ出力ファイルパスを設定した場合は、常に指定したファイルにログを出力するため、ファイルサイズは無限に大きくなっていきます。これを避けるには次節の「ログローテーション」を参照してください。

以下は、app.log というファイルにログを出力する例です。

basicConfig の引数に 「filename=”ログ出力先パス名”」の書式で記述します。フルパスではなくファイル名のみを記載した場合は、実行する Python のファイルと同階層にログファイルが出力されます。

また、basicConfig の引数には「level=logging.WARNING」のよううにして、ログ出力レベルも指定することができます。

 

import logging

# 出力レベルの設定
logging.basicConfig(filename="app.log",level=logging.WARNING)

logging.debug('debug')
logging.info('info')
logging.warning('warnig')
logging.error('error')
logging.critical('critical')

実行結果は以下のようになります。

標準出力にログが出力されていないことに注意してください。

実行結果

実行結果

ファイルへのログ出力結果は以下の通りです。

ファイルのログ出力結果

ファイルのログ出力結果

スポンサーリンク

ログローテーション

ログローテーションの基本

ログローテーションとは、ログが際限なく増え続けることを防ぐために、一定のファイルサイズや期間ごとに古いログを削除したり新しいログで上書きすることを指します。

logging モジュールには RotatingFileHandler というものが備わっており、ログが指定サイズ以上になった時に自動的に新しいログファイルが作成されるようにすることができます。また、無限にファイルが作成されないように、作成されるログファイル数の上限を設定し、ローテーションで使用するようにすることもできます。

RotatingFileHandler の書式を以下に示します。

RotatingFileHandler の書式

class logging.handlers.RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False, errors=None)

指定可能な引数は以下の通りです。

RotatingFileHandler の引数

引数 説明
filename 作成するログのファイル名です。
mode モードが指定されていない場合、「a」が使用されます。aは追加書き込みです。

「w」を指定した場合は、上書きモードになります。

maxBytes ログファイルサイズの最大値です。このサイズを超えたときにログのローテーションが行われます。デフォルト値は0で、この場合はローテーションが行われません。
backupCount ログローテーションによって作成されるファイルの最大数です。バックアップファイル名は filename で指定したファイル名を基準にします。例えば、filenameをapp.logとし、backupCount を 2 とした場合、バックアップファイルはapp.log.1、app.log.2が作成されます。
encoding 出力するログファイルのエンコーディングを指定します。例)utf-8
delay Trueの場合、ファイルを開くのは emit() の最初の呼び出しまで延期されます。
errors エンコーディングエラーの処理方法を決定します。

ログローテーションの例

初めにコード例を示します。

ログローテーションの例 loggingSample.py

import logging
import logging.handlers

# ロガーを取得
log = logging.getLogger(__name__)
# ログ出力レベルの設定
log.setLevel(logging.DEBUG)

# ローテーティングファイルハンドラを作成
rh = logging.handlers.RotatingFileHandler(
        r'./log/app.log', 
        encoding='utf-8',
        maxBytes=100,
        backupCount=3
    )

# ロガーに追加
log.addHandler(rh)

log.debug('===== start =====')

for num in range(30):
    log.debug('debug:{}'.format(str(num)))

log.debug('===== end =====')

5行目は、getLogger メソッドを使用して、ロガーを取得しています。このように、ロガーを取得してログ出力をするのが一般的です。__name__ というのは、このロガーを使用しているモジュール自身の名前を表ます。

7行目は、作成したロガーで使用するログの出力レベルを設定しています。ここでは DEBUG にしています。

10〜15行目は RotatingFileHandler によるローテーティングファイルハンドラの作成です。引数は、ログの出力先(基本のファイル名をapp.log に設定)、出力するファイルのエンコーディング、出力されるファイルサイズの上限(100 byte)、ローテーションするファイルの数(3つ)を与えています。

18行目は、addHandler メソッドを使用して、作成したローテーティングファイルハンドラを追加しています。これを忘れるとログファイルのローテーティングが行われなくなりますので注意が必要です。

20〜25行目は、実際のログ出力です。

 

実行すると、下図のように4つのログファイルが作成されることがわかります。

出力されたログファイル

出力されたログファイル

app.log.3 は以下の通りです。

===== start =====
debug:0
debug:1
debug:2
debug:3
debug:4
debug:5
debug:6
debug:7
debug:8

また、app.logは以下の通りです。

debug:28
debug:29
===== end =====

 

以上のことからわかるように、ログファイルは以下のようにローテンションが行われます。

ログローテーションのイメージ

ログローテーションのイメージ

スポンサーリンク

ローテーティングファイルハンドラによるログ出力レベルの変更

サンプルコードの中で、ログの出力レベルを以下のように設定しました。

# ログ出力レベルの設定 
log.setLevel(logging.DEBUG)

このままでは、ログの出力レベルは最初から最後まで DEBUG となってしまいますが、途中で変更したい場合もあるでしょう。

このような場合は、ローテーティングファイルハンドラの setLevel を使用してログ出力レベルを変更することができます。

以下にサンプルコードを示します。

ログ出力レベルを途中で変更する例 loggingSample.py

import logging
import logging.handlers

# ロガーを取得
log = logging.getLogger(__name__)
# ログ出力レベルの設定
log.setLevel(logging.DEBUG)

# ローテーティングファイルハンドラを作成
rh = logging.handlers.RotatingFileHandler(
        r'./log/app.log', 
        encoding='utf-8',
        maxBytes=100,
        backupCount=3
    )

# ロガーに追加
log.addHandler(rh)

log.debug('===== start =====')

for num in range(30):
    if num > 15: 
        # ログ出力レベルの変更
        rh.setLevel(logging.INFO)
    log.debug('debug:{}'.format(str(num)))
    log.info('info:{}'.format(str(num)))

log.debug('===== end =====')

先ほど示したサンプルコードに、23〜25行目を追加しています。

if文でループのnumが15を超えたときに、ログ出力レベルを変更しています。

このとき、rh.setLevel(logging.INFO) としていますので、num=16以降は debug のログが出力されなくなります。

Please follow and like us:

コメント

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