Python loggingモジュールの効果的な活用手法

Pythonでアプリケーションを開発する際、ログ記録はプログラムの動作状況を把握し、問題発生時に詳細な情報を得るために欠かせない機能です。標準ライブラリとして提供されるloggingモジュールは、柔軟で強力なログ管理を実現します。本稿では、このモジュールの実践的な使い方と効率的な運用のポイントを解説します。

基本的なログ出力

まずはloggingモジュールの最小構成での利用方法を見てみましょう。

import logging

# 基本設定
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.FileHandler("application.log"),
        logging.StreamHandler()
    ]
)

# ログ出力
logging.debug("デバッグ情報")
logging.info("情報メッセージ")
logging.warning("警告メッセージ")
logging.error("エラー発生")
logging.critical("致命的エラー")

このコードでは、ログレベルをINFOに設定し、ファイルとコンソールの両方に出力しています。フォーマットにはタイムスタンプとレベルを含めています。

ログレベルの管理

loggingモジュールが提供する5段階のログレベルは、DEBUGINFOWARNINGERRORCRITICALです。設定したレベル以上のメッセージのみが出力され、それより低いレベルは無視されます。例えばWARNINGを設定すると、DEBUGINFOは記録されません。

カスタムフォーマットの適用

デフォルトのフォーマットではなく、プロジェクトの要件に合わせた出力形式を設定できます。

formatter = logging.Formatter(
    "%(asctime)s | %(name)s | %(levelname)s | %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
)

console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)

logger = logging.getLogger("myapp")
logger.addHandler(console_handler)
logger.setLevel(logging.DEBUG)

この設定では、日時の形式をISO 8601に変更し、ロガー名を追加しています。

ログファイルのローテーション

長時間稼働するアプリケーションでは、ログファイルが肥大化する問題に対処する必要があります。RotatingFileHandlerを使えば、ファイルサイズに基づくローテーションが実現できます。

import logging
from logging.handlers import RotatingFileHandler

logger = logging.getLogger("rotating_logger")
handler = RotatingFileHandler(
    "server.log",
    maxBytes=1024 * 1024,  # 1MB
    backupCount=3
)
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)

for i in range(5):
    logger.info(f"テストログ #{i}")

maxBytesで最大サイズを指定し、backupCountで保持する古いファイルの数を制御します。サイズ超過時には自動的に新しいファイルが生成されます。

実運用でのベストプラクティス

  • 集中管理された設定: プロジェクト全体でログ設定を一元化し、logging.yamllogging.jsonで外部から制御できるようにする。
  • 適切なレベルの選択: 開発中はDEBUG、本番ではINFO or WARNINGを使用し、パフォーマンスと情報量のバランスを取る。
  • 構造化ログの活用: JSON形式で出力し、ログ解析システム(ELK Stackなど)との連携を容易にする。
  • 機密情報の除外: パスワードやAPIキーなどの機密データがログに出力されないよう注意する。
  • 例外トレースの完全取得: logger.exception()を使用してスタックトレースを確実に記録する。

構造化ログの例

import logging
import json

class JSONFormatter(logging.Formatter):
    def format(self, record):
        log_record = {
            "time": self.formatTime(record, self.datefmt),
            "level": record.levelname,
            "message": record.getMessage(),
            "module": record.module,
            "line": record.lineno
        }
        return json.dumps(log_record)

handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger = logging.getLogger("structured")
logger.addHandler(handler)
logger.setLevel(logging.INFO)

logger.info("リクエスト完了", extra={"user": "admin", "duration": 0.23})

この方法で出力されたログは、機械可読性が高く、後続の分析ツールで処理しやすくなります。

タグ: Python logging ログ管理 ローテーション 構造化ログ

6月11日 17:06 投稿