この記事のポイント

  • ロガー構造設計の崩壊パターンをレビュー視点で読み取れる
  • レベル設計責任の分離整理を学べる
  • 実務ログ設計の成長路線を体系化できる
  • PlantUMLでロガー依存構造を可視化整理できる

そもそもloggingとは

Pythonの標準ライブラリ logging は、実行時の情報記録を行う柔軟なロギングシステムです。

  • 階層化されたロガー設計(名前空間ベース)
  • 出力レベル制御(DEBUG, INFO, WARNING, ERROR, CRITICAL)
  • ハンドラー・フォーマッター分離
  • ファイル出力、標準出力、外部転送等が可能
logging基本構成例

import logging

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

logger.info("Service started.")
  • getLogger(__name__):モジュール毎のロガー生成
  • setLevel():出力対象レベル設定
  • info():実際のログ出力

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

logging設計は「設計臭の蓄積領域」になりやすく、レビューアーの重点観察ポイントになります。

レビューアー視点

  • ロガー構造(階層化)が整理されているか
  • レベル設計(通知責任)が統制されているか
  • ハンドラー構成が乱雑化していないか
  • 初期化責任が集中統制されているか
  • 実行時障害時のログ可読性が確保されているか

開発者視点

  • 簡易print代替としてloggingを導入しがち
  • getLogger()の乱立とsetLevel()の多発
  • レベル設計を場当たりで書く習慣
  • ハンドラー設定が分散しやすい
  • 障害時のログ深度に後から困る

ロガー設計崩壊の典型設計臭

崩壊しやすいパターン
  • ファイル内局所setLevel()多発
  • モジュール単位でバラバラにgetLogger()
  • ハンドラーが複数箇所で重複登録
  • 全部INFO中心で実質レベル運用破綻
  • ロガー命名が曖昧・統一ルール不在

崩壊例:局所レベル乱立型

局所乱立例

import logging

logger = logging.getLogger("service.user")
logger.setLevel(logging.DEBUG)  # モジュール個別設定

def create_user():
    logger.debug("create_user called.")
    logger.info("user created successfully.")
@Reviewer
モジュール局所でsetLevel()指定されています。中央初期化統制に統一してください。

問題点

  • setLevel()が各所に分散
  • 結果的に全体ログ粒度が統制不能化

崩壊構造モデル:ロガー乱立依存

UML Diagram

良い設計整理アプローチ

logging設計は以下の整理原則で健全化できます。

① 中央初期化統制(Centralized Initialization)

  • logging_config.py で統一管理
  • レベル・ハンドラー・フォーマッター集中管理

② 命名ルール統一(Hierarchical Namespace)

  • パッケージ名ベース命名統一
  • __name__活用徹底

③ 責務別レベル設計(Responsibility-Driven Leveling)

レベル 責務用途
DEBUG 内部詳細検証
INFO 通常処理進行通知
WARNING 潜在リスク警告
ERROR 処理失敗通知
CRITICAL 即時障害通知

④ ハンドラー分離設計

  • 標準出力、ファイル出力、障害通知先を責務分離

改善例:中央初期化統制版

logging_config.py

import logging
import sys

LOG_FORMAT = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"

def init_logging():
    root_logger = logging.getLogger()
    root_logger.setLevel(logging.INFO)

    formatter = logging.Formatter(LOG_FORMAT)

    stream_handler = logging.StreamHandler(sys.stdout)
    stream_handler.setFormatter(formatter)

    root_logger.addHandler(stream_handler)
  • setLevel()はrootのみ
  • 下位ロガーは継承統制

各モジュール側は統一

service/user.py

import logging

logger = logging.getLogger(__name__)

def create_user():
    logger.info("user created successfully.")
「ロガーは作る、粒度は中央で決める文化」

レビューアーは局所setLevel()消滅文化を推進するとログ健全性が飛躍します。

改善構造モデル:整理後依存統制

UML Diagram

良くない実装例: ケース1(ハンドラー重複)

handler重複例

import logging

logger = logging.getLogger(__name__)
handler = logging.FileHandler("app.log")
logger.addHandler(handler)
@Reviewer
各所で個別ハンドラー登録されています。中央初期化統制へ整理してください。

問題点

  • 出力先管理が分散
  • 重複ハンドリングで多重出力

良くない実装例: ケース2(レベル破綻)

レベル乱用例

import logging

logger = logging.getLogger(__name__)

def process_payment():
    logger.info("connecting payment server")
    logger.info("sending payment data")
    logger.info("payment completed")
@Reviewer
全てINFOで通知粒度が埋没しています。責務別レベル設計を適用してください。

問題点

  • 情報粒度が揃いすぎて重要度差消失
  • 障害時追跡性が劣化

改善例:責務別レベル整理

粒度適用版

def process_payment():
    logger.debug("connecting payment server")
    logger.info("sending payment data")
    logger.info("payment completed")
  • DEBUG:接続開始など詳細系
  • INFO:処理進行系
  • WARNING/ERRORは例外系で使用

観点チェックリスト

まとめ

logging設計は「運用安定性の下支え」となる基盤領域です。
レビューアーは「中央統制文化・粒度統一文化・初期化集中文化」を継続指導することで、運用負荷の少ない健全ログ設計を確立できます。