ドキュメント / 詳細設計 / 非機能系
•
PART 02 / 03
•
2026.06.18
•
20 min read
PART 02 — ログ設計書
ログレベル・フォーマット・保持期間の完全定義
ログ設計書は「障害調査の手がかり」を事前に設計する文書だ。インシデント発生時に「ログが足りない」「フォーマットがバラバラで検索できない」という状況を防ぐために設計段階での定義が必要だ。
ログ設計書の位置づけ
ログは「過去の出来事の記録」だ。適切なログがないと障害調査は「推測」に頼ることになる。設計段階でログの種別・レベル・フォーマット・保持期間を定義し、全員が統一した実装を行うことが重要だ。
⚠️ ログ設計のアンチパターン
開発者ごとにフォーマットが異なる・DEBUG ログが本番に残る・個人情報をそのままログ出力する・ログローテーション設定がない — これらはよくある問題だ。設計書で統一ルールを定めておく。
ログ種別定義
| ログ種別 | 説明 | 出力先 | 保持期間 |
| アクセスログ | 全HTTPリクエスト・レスポンス情報 | /var/log/app/access.log | 90日 |
| アプリケーションログ | 業務処理・エラー・警告 | /var/log/app/app.log | 365日 |
| バッチログ | バッチ処理の開始・終了・処理件数 | /var/log/batch/batch.log | 365日 |
| 監査ログ | 認証・重要データの参照・更新操作 | DB: audit_logs テーブル | 5年 |
| パフォーマンスログ | レスポンスタイム・DB実行時間 | /var/log/app/perf.log | 30日 |
ログレベル定義
| レベル | 用途 | 本番出力 | 例 |
| ERROR | 即時対応が必要な障害 | ◎ | DB接続失敗・外部IF障害・未捕捉例外 |
| WARN | 監視が必要な警告(即時対応不要) | ◎ | リトライ発生・レスポンス遅延・在庫残少 |
| INFO | 業務的な重要イベント | ◎ | 注文確定・バッチ開始/終了・ログイン成功 |
| DEBUG | 開発・調査用の詳細情報 | ✗(開発環境のみ) | SQL クエリ詳細・変数値・処理ステップ |
| TRACE | 最詳細のデバッグ情報 | ✗ | メソッド入出力・ループ処理詳細 |
ログフォーマット定義(JSON 構造化ログ)
■ 採用フォーマット: JSON(構造化ログ)
理由: CloudWatch Logs / Datadog / Elasticsearch で自動パースが可能
■ フィールド定義
{
"timestamp": "2026-06-18T12:00:00.123Z", // ISO8601 UTC
"level": "ERROR", // ERROR/WARN/INFO/DEBUG
"logger": "com.example.order.OrderService",// クラス名
"traceId": "abc123def456", // リクエスト単位の一意ID
"userId": 12345, // 操作ユーザーID(null可)
"errorCode": "BIZ_001", // エラーコード(エラー時のみ)
"message": "在庫引当失敗 product_id=456", // ログメッセージ
"context": { // 追加コンテキスト
"product_id": 456,
"requested": 10,
"available": 3
},
"elapsed_ms": 23 // 処理時間(ms)
}
■ 禁止事項
- パスワード・APIキーの出力
- クレジットカード番号・銀行口座番号
- マイナンバー・パスポート番号
- メールアドレス(アクセスログを除く)
※ ユーザーIDのみで追跡可能にする設計とする
出力先・保持期間
| 項目 | 設定値 |
| ログローテーション | 日次(00:00)にローテーション |
| 圧縮 | ローテーション後に gzip 圧縮 |
| 最大ファイルサイズ | 500MB(超過時は即時ローテーション) |
| リモート転送 | CloudWatch Logs に 15分以内に転送 |
| アラート閾値 | ERROR が 1分間に 10件以上で PagerDuty 通知 |
必須出力ログ一覧
| イベント | レベル | 必須フィールド |
| ログイン成功 | INFO | userId, ip, user_agent |
| ログイン失敗 | WARN | loginId(マスク), ip, reason |
| 注文確定 | INFO | userId, orderId, totalAmount |
| 外部IF呼び出し | INFO | ifId, elapsed_ms, status |
| バッチ開始 | INFO | batchId, targetDate |
| バッチ終了 | INFO | batchId, processedCount, elapsed_ms |
| 未捕捉例外 | ERROR | errorCode, exception, stackTrace |
Python Tips — structured logging の実装
Python — JSON 構造化ログの設定と使い方
"""
Python での JSON 構造化ログ実装
pip install python-json-logger
"""
import logging, json
from datetime import datetime, timezone
from pythonjsonlogger import jsonlogger
class AppJsonFormatter(jsonlogger.JsonFormatter):
def add_fields(self, log_record, record, message_dict):
super().add_fields(log_record, record, message_dict)
log_record["timestamp"] = datetime.now(timezone.utc).isoformat()
log_record["level"] = record.levelname
log_record["logger"] = record.name
# traceId はリクエストスコープから取得(例: contextvars)
import contextvars
trace_id = contextvars.copy_context().get(
contextvars.ContextVar("trace_id"), None)
if trace_id:
log_record["traceId"] = trace_id.get(None)
def setup_logging(level=logging.INFO):
handler = logging.StreamHandler()
handler.setFormatter(AppJsonFormatter(
"%(timestamp)s %(level)s %(logger)s %(message)s"
))
logging.basicConfig(level=level, handlers=[handler])
setup_logging()
logger = logging.getLogger("com.example.order.OrderService")
# 使い方
logger.info("注文確定", extra={"userId": 12345, "orderId": 67890, "totalAmount": 11000})
logger.warning("在庫残少", extra={"product_id": 456, "remaining": 5})
logger.error("在庫引当失敗",
extra={"errorCode": "BIZ_001",
"context": {"product_id": 456, "requested": 10, "available": 3}})
# 出力例
# {"timestamp": "2026-06-18T03:00:00.123Z", "level": "INFO",
# "logger": "com.example.order.OrderService",
# "message": "注文確定", "userId": 12345, "orderId": 67890, "totalAmount": 11000}
レビューチェックリスト
| # | チェック項目 |
| 1 | ログ種別・出力先・保持期間が定義されているか |
| 2 | ログレベルの判断基準が定義されているか |
| 3 | ログフォーマットが統一されているか(JSON推奨) |
| 4 | 個人情報・機密情報のログ出力禁止が明記されているか |
| 5 | ローテーション・圧縮・保持期間が定義されているか |
| 6 | アラート通知の閾値・通知先が定義されているか |