この記事のポイント

  • エラーログと運用ログの設計責任をレビュー視点で整理できる
  • 目的別ログ設計の分離技法を学べる
  • 実務での運用ログ健全化の考え方を体系化できる
  • PlantUMLでログ依存構造を可視化整理できる

そもそもログの役割とは

Pythonに限らず、アプリケーションが出力するログは大きく二系統に整理できます。

ログ種別 主目的 主な出力対象 主な利用者
エラーログ 障害分析・異常通知 SRE・開発者 システム管理者・障害担当
運用ログ 業務進行監視・定常確認 オペレーター・運用担当 ビジネスサイド・運用部門

この目的差を設計上整理しないまま実装が進むと、「ログが読めば読むほど分からなくなる設計臭」が発生します。

なぜこれをレビューするのか

ログ出力は「運用中に最も長く影響し続ける実行系設計責任」です。
レビューアーは以下の整理視点を常に持つ必要があります。

レビューアー視点

  • 出力先と目的が混在していないか
  • 運用者と障害通知先の分離が行われているか
  • レベル運用(INFO/ERROR等)の責務設計が適切か
  • 出力媒体(ファイル、監視系、通知系)が整理されているか
  • 統計系ログと障害系ログが混ざっていないか

開発者視点

  • print()代替で安易にlogging導入しがち
  • INFO中心で全部吐けば良いという誤解
  • ERRORは例外時のみ出せば良いと思いがち
  • 障害通知連携(Sentry、監視連携)まで設計を進めにくい

ログ設計崩壊の典型設計臭

崩壊しやすいパターン
  • INFOレベル一色で実行中全件埋没
  • WARNING/ERROR粒度が曖昧化
  • 運用オペレーションログに障害系が混入
  • SRE系通知連携不在
  • API単位でバラバラ出力方針

崩壊例:粒度混在ログ

混在ログ例

import logging

logger = logging.getLogger(__name__)

def register_user(user_id):
    logger.info("starting register_user")
    logger.info("connecting database")
    logger.info("inserting user")
    logger.info("finished register_user")
@Reviewer
INFOレベルに運用ログも内部処理ログも混在し粒度が曖昧です。責務分離整理を検討してください。

問題点

  • 全てINFOでは重要ログが埋没
  • 障害発生時に追跡困難

崩壊構造モデル:粒度混在構造

UML Diagram

責任分離の設計整理原則

ログ出力は「誰に通知する責任か?」を基準に設計整理します。

① ログ層整理

ログ層 主担当 主出力レベル 出力先
運用層 運用担当 INFO/WARNING 運用ログ
障害層 SRE・開発 ERROR/CRITICAL エラーログ・監視系
開発層 開発デバッグ DEBUG 開発環境限定

② 出力媒体整理

  • 運用ログ:ファイル出力・オペレーター確認用
  • エラーログ:監視通知系(例: Sentry, Slack通知)
  • 開発ログ:標準出力・CIログ確認用

③ 例外ハンドリング整理

  • 障害系は例外経路でERROR通知
  • 正常系ログは不要に内部処理を追わない

改善例:分離整理版

改善ログ実装

import logging

logger = logging.getLogger(__name__)

def register_user(user_id):
    logger.info(f"ユーザ登録開始 user_id={user_id}")
    try:
        insert_user(user_id)
        logger.info(f"ユーザ登録成功 user_id={user_id}")
    except DuplicateUserException:
        logger.warning(f"既存ユーザ user_id={user_id}")
    except Exception as e:
        logger.error(f"ユーザ登録失敗 user_id={user_id}: {e}")
        raise
正常系と障害系をログ責務で明確に分ける文化

レビューアーは正常完了ログと障害ログが分離されているかを常に確認すると設計健全性が高まります。

改善構造モデル:分離整理版

UML Diagram

良くない実装例: ケース1(例外丸投げ)

例外放置型

def process_order(order_id):
    logger.info(f"processing order {order_id}")
    insert_order(order_id)  # 例外発生可能
@Reviewer
例外捕捉なくERROR通知経路が消失しています。障害通知責務を明示してください。

問題点

  • 例外発生時にログ通知不備
  • エラー粒度が消失

改善例:障害通知整理

障害通知整理版

def process_order(order_id):
    logger.info(f"processing order {order_id}")
    try:
        insert_order(order_id)
    except Exception as e:
        logger.error(f"order processing failed: {e}")
        raise

良くない実装例: ケース2(障害系と統計系混在)

統計混在例

def process_payment(user_id, amount):
    logger.info(f"payment started user_id={user_id} amount={amount}")
    logger.info(f"payment amount={amount}")
    logger.info(f"payment finished user_id={user_id}")
@Reviewer
統計的な運用情報がINFOに埋没しています。運用ログと統計系は出力責務を分離してください。

改善例:統計系分離

統計系分離版

def process_payment(user_id, amount):
    logger.info(f"payment started user_id={user_id}")
    metrics.record_payment(amount)  # 統計系別途設計
    logger.info(f"payment finished user_id={user_id}")
  • 統計はmetrics系モジュールに整理
  • ログ出力は運用情報のみに限定

観点チェックリスト

まとめ

ログ設計は「保守フェーズの実力が最も出る領域」です。
レビューアーは「責務別出力文化・粒度文化・通知経路文化」を徹底教育することで、障害検知力の高いプロダクション品質を築くことができます。