ログ運用仕様
Parky 全ランタイム(Astro SSG / Vite React SPA / Cloudflare Workers / Flutter)に わたるログ出力の共通スキーマと運用ルール。
各ランタイムは異なるロガー実装を使ってよい。ただし出力する JSON イベントは本文書のスキーマに従う。 これにより将来どのログ集約基盤に送っても串刺し検索ができる。
1. 共通スキーマ
すべてのロガーは次の JSON を 1 イベント = 1 行で stdout に出す:
{
"level": "debug|info|warn|error",
"time": "2026-04-17T10:00:00.123Z",
"service": "admin|home|api|mobile",
"env": "dev|staging|prod",
"msg": "人が読める短い説明",
"scope": { "userId": "...", "requestId": "..." },
"error": { "name": "...", "message": "...", "stack": "..." },
"extra": { "任意のコンテキスト": "..." }
}
必須フィールド
| キー | 意味 |
|---|---|
level |
ログレベル(下記 § 2) |
time |
ISO 8601 UTC |
service |
どのランタイムから出たか |
env |
環境(import.meta.env.MODE 等から) |
msg |
1 行の説明文(日本語OK) |
任意フィールド
| キー | 意味 |
|---|---|
scope |
リクエスト/セッション全体を通したコンテキスト(user_id / trace_id 等) |
error |
Error オブジェクトのシリアライズ(error レベル時は推奨) |
extra |
その場限りの追加情報 |
禁止: PII(メール・氏名・電話)をそのまま出力しない。必要なら user_id のみ。
2. ログレベル
| level | 用途 | 本番での扱い |
|---|---|---|
debug |
開発時の詳細追跡 | 出力しない |
info |
重要な状態遷移(セッション開始、ジョブ完了) | 出力 |
warn |
想定内の異常(retry、フォールバック発動) | 出力 |
error |
想定外のエラー(Sentry へも自動転送) | 出力 + Sentry |
3. 業務監査ログは分離する
ロガー基盤と業務監査は別物:
| 種類 | 保存先 | 目的 |
|---|---|---|
| アプリログ(本ドキュメント) | stdout → 集約基盤 | 運用・障害対応 |
| ユーザー行動ログ | user_activity_logs テーブル |
分析・バッジ付与 |
| 管理者操作ログ | admin_activity_logs テーブル |
監査・変更追跡 |
ロガーでアプリログを出す際に、業務監査テーブルにも書いてしまわないこと。
業務監査は専用 API(logAdminActivity() 等)経由で明示的に行う。
4. ランタイム別の実装指針
4.1 admin / home(TypeScript ブラウザ + Astro SSR)
@parky/loggerパッケージを使う(web/packages/logger/)- ブラウザでは console に出力 +
errorは Sentry に自動転送 - Astro SSR(Node)も同じパッケージで動作
- 使用例:
import { createLogger } from '@parky/logger'; const log = createLogger({ service: 'admin', env: import.meta.env.MODE }); log.info('ユーザー更新完了', { extra: { user_id } }); log.error(err, { scope: { action: 'user.update_status' } });
4.2 Cloudflare Workers BFF(Hono)
api/src/lib/logger.tsに薄いラッパーを置いてconsole.log(JSON.stringify({...}))で stdout 出力- スキーマは本ドキュメントに準拠
wrangler.tomlで[observability] enabled = trueを入れてあるので、Cloudflare Dashboard の Workers Observability から構造化ログとして検索可能- Logpush を繋いで外部基盤(Datadog / Logtail 等)に流す設計も可能(未配線)
4.3 Flutter(Dart)
loggerパッケージ(Dart)を使用- 本番クラッシュは Firebase Crashlytics に送る
- JSON 出力は dev では不要、本番でログ集約基盤にパイプするタイミングで検討
5. 転送先(バックエンド)
現時点:
- Sentry:
@sentry/react導入済み(DSN 未設定時は素通り) - stdout: ブラウザコンソール / Cloudflare Pages 実行ログ / Cloudflare Workers Observability
将来(別タスク):
- ログ集約: Datadog / Logtail / Grafana Loki 等を 1 つ選定し Cloudflare Logpush で流す
trace_idを跨がせて OpenTelemetry 対応
6. 疎結合の原則
@parky/logger のコア実装は転送先(Sentry / CloudWatch 等)を知らない。
転送は Transport 関数として差し替え可能:
const log = createLogger({
service: 'admin',
env: 'prod',
transports: [consoleTransport(), sentryTransport()], // 後付けで追加
});
これにより:
- コアは依存ゼロで変更不要
- 転送先の切替はアプリ起動時の設定のみ
- テスト時は transports を空にできる
7. 命名規則(参考)
msg は短く動作・結果を書く:
good: "駐車セッション作成失敗"
good: "role.update_permissions 成功"
bad: "エラーが発生しました"
bad: "The user (id=abc) tried to update ..." ← 詳細は extra/scope へ
scope.action はドット区切りの resource.verb を推奨:
user.update_status / role.update_permissions / vehicle.soft_delete