スタックトレース完全入門
スタックトレースは「エラーが辿ってきた道筋」を可視化するデバッグの羅針盤である。
1. スタックトレースとは何か
-
定義: 例外が発生した瞬間の 呼び出し階層 (stack frame) を上から順に文字列化したもの。
-
含まれる情報
- ファイルパス・行番号
- 関数/メソッド名
- 呼び出し順序(上位 → 下位)
-
得られるメリット
- バグ再現の最短手掛かり
- 影響範囲の特定 (自前コード or ライブラリ?)
- パフォーマンス・責務分割のヒント
Traceback (most recent call last):
File "/app/api/user.py", line 45, in get_user
user = await service.get_user_by_id(user_id)
File "/app/service/user_service.py", line 88, in get_user_by_id
raise NotFoundError(f"User {user_id} not found")
NotFoundError: User 123 not found
2. Web API におけるスタックトレースの重要性
-
マイクロサービス時代のデバッグ: API 境界を越えると再現が難しい → サーバー側のトレースが生命線。
-
可観測性 (Observability) 三種の神器
- メトリクス: 量的変化を監視
- ログ: 状態変化を時系列で記録
- トレース (分散トレーシング) / スタックトレース: 失敗パスを可視化
-
セキュリティ注意点: 本番レスポンスに露出するとファイル構成やパッケージバージョンが漏洩 ➜ マスキング or カスタムエラー が必須。
3. Docker × FastAPI + Uvicorn でのスタックトレース制御
3-1 運用ポリシー
-
開発: すぐ見たい →
debug=True+ 制限なし - 本番: ユーザーには隠し、ログには残す
3-2 主要スイッチ
| レイヤ | 設定例 | 効果 |
|---|---|---|
| FastAPI | app = FastAPI(debug=False) |
HTTP 500 で詳細非表示 |
| Uvicorn | --log-level info |
標準出力の詳細度 |
| Python |
PYTHONFAULTHANDLER=1sys.tracebacklimit = 5
|
致命的例外時に強制ダンプ / 深さ制限 |
| Gunicorn | --log-level info |
Worker 全体のログ深度 |
3-3 Dockerfile スニペット
# ---------- build ----------
FROM python:3.11-slim AS runner
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# ---------- runtime ----------
ENV PYTHONFAULTHANDLER=1 \
TRACEBACKLIMIT=0 # 本番では 0 でフレーム非表示
CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", \
"main:app", "-b", "0.0.0.0:8000", "--log-level", "info"]
4. Node.js (Express / NestJS) でのスタックトレース制御
4-1 運用ポリシー
-
開発:
NODE_ENV=development+Error.stackTraceLimit = Infinity -
本番:
NODE_ENV=productionで自動的に stack 隠蔽 → さらに独自 middleware で完全マスク
4-2 設定比較表
| レイヤ | 開発 (dev) | 本番 (prod) |
|---|---|---|
| V8 | Error.stackTraceLimit = Infinity |
デフォルト (10) |
| Node flags | node --trace-uncaught |
--abort-on-uncaught-exception |
| Express MW | JSON で err.stack 返す |
固定メッセージ "Internal Server Error" |
| Env 変数 | ERROR_STACKS=true |
ERROR_STACKS=false |
4-3 Middleware 例
app.use((err, req, res, next) => {
const expose = process.env.ERROR_STACKS === 'true';
console.error(err); // サーバー側には常に出力
res.status(500).send(
expose ? err.stack : 'Internal Server Error'
);
});
5. 明日から使うレシピ
-
IDE ジャンプ: VS Code / PyCharm でスタック行をクリック → 該当ソースへ。
-
APM 連携: Sentry、Datadog を導入し、“エラーごとの fingerprint” でハッシュ化集約。
-
サンプラー: 🔧 py-spy (Python) / clinic flame (Node) で実行中プロセスに安全 attach。
-
CI テスト失敗時の自動収集:
-
pytest -vv --log-cli-level=ERRORでトレース全文を GitHub Actions アーティファクトへ保存。
-
-
再発防止: 似た stackhash が 3 回以上上がったら警告 → Jira チケット自動生成。
6. まとめ
- 概念: スタックトレース = 例外が通った“呼び出し履歴”。
- 重要性: Web API では多層構造ゆえ、再現よりトレースが解析の鍵。
-
FastAPI:
debugとTRACEBACKLIMITを切り替え、ログは常にフル出力。 -
Node.js:
NODE_ENVと middleware でレスポンス露出を完全制御。 - 運用: "ユーザーには隠し、ログと APM には詳細を残す" が鉄則。