# ログ運用ガイド

本ドキュメントは B20 方針および AGENTS.md のロギング原則を踏まえ、開発・運用メンバーが一貫したログレベル選定と出力形式に従えるようにまとめたものです。

## ログレベルの基準

- **DEBUG**: デバッグ専用の詳細情報。大量出力を許容するが本番では通常無効化する。
- **INFO**: 正常系の進行を追跡するための要点。開始・終了・主要ビジネスイベントを記録する。
- **WARNING**: 想定内の異常や劣化状態。リトライで回復し得る状況やしきい値超過を扱う。
- **ERROR**: 想定外の失敗。処理は不完全で運用アラートの対象。
- **CRITICAL**: サービス継続不能・データ喪失・プロセス起動不能など即時対応が必要な状態。

## 出力ポイントの推奨

- **起動/終了**: 主要バージョン・設定のロード結果・終了処理を `INFO` で出力。起動失敗は `CRITICAL`。
- **外部境界 (HTTP/CLI/メッセージング)**: リクエスト受信とレスポンス送信を `INFO`。4xx 系は `WARNING`、5xx/タイムアウトは `ERROR`。ヘッダー・本文は `DEBUG` とし、PII は必ずマスクする。
- **データストア**: クエリ本文は `DEBUG`、閾値超過は `WARNING`、失敗は `ERROR`。マイグレーション開始/完了は `INFO`。
- **ビジネスイベント**: 重要イベント (注文確定など) を `INFO`。期待された拒否は `WARNING`。金融・監査用途は専用チャンネルへも送信する。
- **例外処理**: フォールバック成功は `WARNING`、未処理例外は `ERROR` (スタックトレース必須)。進行不能は `CRITICAL`。
- **ジョブ/バッチ**: ジョブの開始・完了を `INFO`。リトライは `WARNING`、リトライ尽きた場合は `ERROR`。
- **状態遷移/並行制御**: 明示的な状態遷移を `INFO`。ロック待ち長期化は `WARNING`、デッドロックは `ERROR`。
- **セキュリティ**: ログイン失敗や拒否は `WARNING`、ブルートフォース検知やポリシー違反は `ERROR`。

## 運用ルール

- 本番環境では既定で `INFO` 以上を残し、調査時のみ `DEBUG` を一時的に有効化する。
- ログは構造化 (JSON) し、`request_id` / `user_id` / `event` / `elapsed_ms` などのコンテキストを `extra` で渡す。
- 高頻度イベントはサンプリングを行い、同一エラーは件数・期間を集約する。
- 機微情報は常にマスクし、ダンプ系 `DEBUG` でも例外を設けない。
- 遅延しきい値は各サービスで明示し、超過時は `extra={"elapsed_ms": ...}` を添える。

## 実装ガイドライン

- Python では `noveler.infrastructure.logging.unified_logger.get_logger(__name__)` を利用する。独自に `logging.getLogger` や `Console()` を生成しない。
- `logger.info("...")` の際は `extra={"extra_data": {...}}` を渡して構造化フィールドを付加する。
- テスト実行 (`/test`, `bin/test` など) 中は `scripts/run_pytest.py` が `reports/` 配下に JSON ログ (`artifacts/<run_id>/pytest*.log`) を配置し、`llm_summary.attachments.jsonl` にマニフェストを追記する。
- ログ添付を無効化したい場合は `LLM_ATTACH_LOGS=0` を設定する。pytest-xdist 利用時はワーカーごとに `pytest_gw*.log` が生成される。

### Console 出力のエラーハンドリング

Rich Console を利用した出力 (`console.print()`) は、pytest capture や stdout/stderr 閉鎖により `OSError` / `BrokenPipeError` で失敗することがあります。特に MCP サーバーなど I/O が混在する環境では注意が必要です。

**エラーメッセージ喪失を防ぐため、以下の対応を推奨**:

- **MCP サーバーの初期化フェーズ（エラーハンドリング）**: `safe_console_print()` を使用する。
  ```python
  from noveler.presentation.shared.shared_utilities import safe_console_print

  # MCP 未インストール時など初期化エラー
  if not MCP_AVAILABLE:
      safe_console_print("エラー: MCPライブラリが利用できません")
      return 1
  ```

- **動作原理**: `safe_console_print()` は以下を保証:
  - `console.print()` 成功時: `True` を返す
  - `console.print()` が I/O 例外で失敗時: `logger.error()` へ自動フォールバック、`False` を返す
  - スレッドセーフ（double-checked locking で複数スレッド環境対応）

- **呼び出し側の責務**:
  ```python
  if not safe_console_print(message):
      # Optional: 失敗時の追加処理
      sys.exit(1)  # または他の recovery 処理
  ```

- **テスト環境での注意**:
  - pytest capture により stderr/stdout が一時的に閉鎖される場合があります
  - `safe_console_print()` は自動的に logger へフォールバックするため、テスト中もエラーメッセージが記録されます
  - テスト実行後に `reports/llm_summary.{jsonl,txt}` でログを確認可能

## 関連資料

- `AGENTS.md` – プロジェクト全体の開発原則
- `README.md` – テスト実行フローと生成物
- `docs/B20_Claude_Code開発作業指示書.md` – B20 準拠の開発プロセス詳細
