始めに
Pythonで開発する際、ログの書き方や設定など毎回調べながら書いているので一度よく使用する設定をまとめておこうと思います
まずlogging
の基本的な書き方を紹介したあとに、ファイル出力のより詳細なカスタマイズの方法についてサンプルコードを提示しながらざっくりとご紹介させていただきます
テストを行った環境
- OS: Windows 11
- Python: 3.13.5
ログの記録を始めるための基本の書き方
logging --- Python用のログ記録手段にも書かれている通りなのですが、複数のモジュールから、特定のファイルにログを記録していきたいとき、細かいことは気にせずにとりあえずログを取っていきたいときは以下のように書けばOKだと考えています
import logging
import mylib
logger = logging.getLogger(__name__)
logging.basicConfig(
filename="myapp.log",
format="{asctime} [{levelname}] {name}: {message}",
datefmt="%Y-%m-%d %H:%M:%S",
style="{",
level=logging.INFO,
encoding="utf-8",
)
def main():
logger.info("Started")
mylib.do_something()
logger.info("Finished")
if __name__ == "__main__":
main()
import logging
logger = logging.getLogger(__name__)
def do_something():
logger.info("Doing something")
2025-08-22 10:30:36 [INFO] __main__: Started
2025-08-22 10:30:36 [INFO] mylib: Doing something
2025-08-22 10:30:36 [INFO] __main__: Finished
ロギングのポイント
意識するポイントは大きく3つくらいかな?と思います
1. ロガーをモジュールごとに分けて作成する
各モジュールの先頭でgetLogger(name)
を使用してロガーのインスタンスを作成しましょう
logger = logging.getLogger(__name__)
2. ログの出力はlogger
+ レベルで行う
上記のように作成したlogger
インスタンスとレベルに適した関数によってログを出力します
出力したログは3. で説明するファイル/ ストリームに出力されます
logger.debug("開発者向けの情報")
logger.info("想定通りのことが起こったことの確認")
logger.warning("ソフトウェアは期待通り動作するが、想定外の事象・将来の問題を示唆")
logger.error("重大な問題により、ソフトウェアがある機能を実行できない")
logger.critical("プログラムが実行を続けられないほどのエラー")
3. basicConfigはエントリーポイントの1箇所だけに書く
basicConfig
のサンプルは以下のとおりです
logging.basicConfig(
filename="myapp.log", # 出力したいファイル名
format="{asctime} [{levelname}] {name}: {message}", # ログのフォーマット
datefmt="%Y-%m-%d %H:%M:%S", # 日時のフォーマット
style="{", # formatの変数埋め込みのスタイル 他にも $ や % を使った表記あり
level=logging.INFO, # 指定したレベル以上のログのみ出力
encoding="utf-8",
)
このbasicConfig
ですが、あるモジュールに関してログの一部だけフォーマットを変えたい、出力先を変えたい、などの理由からプロジェクト内で2回以上logging.basicConfig
を実行しないようにしましょう
basicConfig
の役割はルートロガーの基本的な構成を行う関数で、標準出力やファイル出力を行うためのハンドラーをルートロガーに追加します
そしてルートロガーにハンドラーが既に設定されている場合は(force=True
にしない限り)何もされません
とはいうもののモジュールの読み込み順などの関係で、意図しないフォーマットや出力先にログが出力される可能性がありますので注意しましょう
フォーマットについてはこちら
出力先やフォーマットを分けたい場合は…
basicConfig
は使用せずに、logging.FilHandler
を使用して細かいログ出力設定を行いましょう
※ ルートロガーには全てのログが渡されるので、basicConfig
を使用するとログが2重3重で出力されるので注意しましょう
以下ハンドラーを使用した出力設定のサンプル
import logging
import mylib
logger = logging.getLogger(__name__)
# ファイル出力用のハンドラーを作成
file_handler = logging.FileHandler("myapp.log")
file_handler.setFormatter(
logging.Formatter("{asctime} [{levelname}] {name}: {message}", style="{")
)
# ハンドラー追加(複数個も可能)
logger.addHandler(file_handler)
logger.setLevel(logging.INFO)
import logging
logger = logging.getLogger(__name__)
# 出力先は同じところ
file_handler = logging.FileHandler("myapp.log")
#フォーマットをちょっとだけ変更
file_handler.setFormatter(logging.Formatter("[{levelname}]: {message}", style="{"))
logger.addHandler(file_handler)
logger.setLevel(logging.INFO)
def do_something():
logger.info("Doing something")
2025-08-22 11:43:24,741 [INFO] __main__: Started
[INFO]: Doing something
2025-08-22 11:43:24,741 [INFO] __main__: Finished
ファイルサイズ・期間でログを分割するためのローテーティング
この章ではファイルのサイズや期間毎に分割されたログの出力や、一定期間・一定数以上のログの削除の方法について紹介します
使用するのはRotatingFileHandler
とTimedRotatingFileHandler
の2つのHandlerです
RotatingFileHandler(サイズベースのローテーション)
特徴
- ファイルのサイズが指定したサイズに達したタイミングで、新しいファイルに切り替える
- 古いログファイルはxxx.1, xxx.2, ...のように保存される
以下のサンプルを実行するとapp.log, app.log.1, app.log.2, app.log.3の4つのログファイルが作成されます
バックアップの際に設定されるファイル名のフォーマットは多分変更できない?(例えばapp.log.1
--> 1_app.log
のように)
また新しいファイルが作成されるタイミングではバックアップ用のファイルはリネームされ、backuupCount
を超えたファイルは削除されます
import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
hander = RotatingFileHandler("app.log", maxBytes=1000, backupCount=3)
hander.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s"))
logger.addHandler(hander)
for i in range(100):
logger.info("rotation sample")
TimedRotatingFileHandler(時間ベースのローテーション)
特徴
- 時間の経過に応じてログファイルを切り替える
- ファイル名に日付や時間が付加される
ログファイルを分割するインターバルの設定についてはこちらをご確認ください
※ halder.suffix = ...
でファイル名の末尾につける日時のフォーマットを変更できるのですが、私の環境だとコメントアウトしてある形式以外でしたときはbackupCount
を超えてもファイルの削除が実行されませんでしたので基本的に設定しなくても良いと思います
from logging.handlers import TimedRotatingFileHandler
import logging
import time
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
handler = TimedRotatingFileHandler(
"app.log", when="S", interval=3, backupCount=2, encoding="utf-8"
)
formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")
handler.setFormatter(formatter)
# handler.suffix = "%Y-%m-%d_%H-%M-%S"
logger.addHandler(handler)
for i in range(10):
logger.info("time rotation sample")
time.sleep(1)
まとめ
- Pythonでログの記録を行うための基本について紹介しました
- FileHandler, (Timed)RotatingFileHandlerについて使い方を紹介しました
- 今回紹介した内容ではログファイルの作成と削除を行えます
- 今回紹介した内容の他にもコマンドライン上に出力したり、ネットワークソケットに送信したりなども行うことができますので、興味があれば
logging.handlers
で調べてみてください
ご不明な点や間違っている内容がありましたらアドバイスいただけますと幸いです