もう迷わない!Python loggingベストプラクティス10選

python

はじめに

Pythonのloggingモジュールは強力ですが、「結局どう使えばいいの?」と迷う人は少なくありません。
特にチーム開発や本番運用では、適切なロギング戦略を取らないとエラーの特定が遅れる・ログが読みにくい・不要な情報で肥大化するといった問題が発生します。

この記事では、Pythonのloggingを使いこなすためのベストプラクティス10選を、実務で使えるサンプルコード付きで解説します。


ベストプラクティス 1. logging.basicConfigではなくLoggerインスタンスを使う

多くの入門記事でlogging.basicConfig()が紹介されますが、本格的な開発ではモジュールごとに専用のLoggerを作成する方が管理しやすいです。

import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(name)s: %(message)s')
handler.setFormatter(formatter)

logger.addHandler(handler)

ポイント:

  • __name__でモジュール名をログに自動付与
  • 他モジュールとのログ設定の衝突を防げる

ベストプラクティス 2. ログレベルの使い分けを明確化

ログレベルの基準をチーム内で統一しましょう。

レベル用途例
DEBUG開発・デバッグ用詳細情報
INFO正常動作の記録(処理完了、開始など)
WARNING想定外だが動作継続可能な状態
ERROR処理が失敗したがアプリ継続可能
CRITICALアプリの停止を伴う重大エラー

ベストプラクティス 3. タイムスタンプとモジュール名を必ず記録

実運用では、いつ・どこで・何が起きたかが分かるログが重要です。

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

ベストプラクティス 4. ファイル出力とコンソール出力を併用

開発時はコンソール、本番ではファイルに保存することが多いです。両方に同時出力も可能。

file_handler = logging.FileHandler('app.log')
file_handler.setFormatter(formatter)

logger.addHandler(handler)       # コンソール
logger.addHandler(file_handler)  # ファイル

ベストプラクティス 5. ローテーションでログ肥大化を防ぐ

RotatingFileHandlerを使えば、ログファイルが一定サイズを超えると自動でローテーションできます。

from logging.handlers import RotatingFileHandler

rot_handler = RotatingFileHandler('app.log', maxBytes=5_000_000, backupCount=5)
rot_handler.setFormatter(formatter)
logger.addHandler(rot_handler)

ベストプラクティス 6. 環境変数でログレベルを切り替え

本番と開発でログ量を変えたい場合は、環境変数で制御。

import os
log_level = os.getenv('LOG_LEVEL', 'INFO').upper()
logger.setLevel(getattr(logging, log_level))

ベストプラクティス 7. 例外ログはlogger.exceptionで

例外スタックトレースを自動で記録できます。

try:
    1 / 0
except ZeroDivisionError:
    logger.exception("ゼロ除算エラーが発生しました")

ベストプラクティス 8. JSON形式でログを構造化

機械的に解析しやすいログは運用効率を上げます。

import json

class JsonFormatter(logging.Formatter):
    def format(self, record):
        log_obj = {
            'time': self.formatTime(record),
            'level': record.levelname,
            'name': record.name,
            'message': record.getMessage()
        }
        return json.dumps(log_obj)

json_handler = logging.StreamHandler()
json_handler.setFormatter(JsonFormatter())
logger.addHandler(json_handler)

ベストプラクティス 9. 外部サービス連携(Slack, Sentryなど)

エラーをリアルタイム通知することで復旧が早まります。
例:Slack Webhookで通知するカスタムHandler。


ベストプラクティス 10. 設定ファイル(YAML/JSON)で管理

コードに直接書かず、logging.config.dictConfigで設定を読み込むと柔軟に変更可能。


まとめ

  • ログは後から原因追跡するための生命線
  • 統一ルール自動化で、チーム全体の運用負荷を下げられる
  • basicConfigから卒業し、モジュール単位のLoggerと設定ファイル管理へ移行すべき

📌 おすすめ図解(生成可能)

  • ログレベル別の運用フロー図
  • ログ出力先構成図(コンソール・ファイル・外部サービス)
  • RotatingFileHandlerの仕組み図

もし希望があれば、この内容に図解付きの完全版を作って、
SEOメタディスクリプションや見出しタグ最適化もできます。

次は、この記事を図解付きに拡張しますか?
それともブログ投稿用のSEO最適化HTML版にしますか?

コメント

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