正規のワイドイベント
正規のワイド イベントは、1 つの完了した作業単位を、その結果を説明するために必要なコンテキストとともに記述します。アプリケーションは、切断された「開始」、「データベース呼び出し」、および「終了」メッセージからリクエストを再構築する代わりに、ルート、アカウント、リリース、期間、ステータス、および分類された失敗コンテキストを含む 1 つのリクエスト結果を出力します。
このパターンは、正規ログ行、構造化イベント、またはワイド イベントとも呼ばれます。 Stripe では、リクエストの重要なコンテキストを 1 か所に収集する方法として正規のログ行について説明しました。 Honeycomb は、可観測性の基礎としてコンテキストが豊富な構造化イベントを使用します。の OpenTelemetry ログ データ モデル は、ログとトレースを関連付けることができる標準的な表現を提供します。名前とトランスポートは異なりますが、有益な設計上の質問は同じです。つまり、物語を検索せずに、1 つのレコードで意味のある結果を説明できるかということです。
「幅広い」とは、イベントに多くの目的のある分野が含まれる可能性があることを意味します。メモリ内のすべてのオブジェクトをコピーするという意味ではありません。
イベント粒から始める
イベント粒は1列で表されるものです。フィールドを選択する前に書き留めてください。有用な穀物には次のようなものがあります。
- 1 つの API リクエストが最終結果に達しました
- 1 つのバックグラウンド ジョブが完了したか、再試行を使い果たしました
- 1 つの Webhook 配信が処理、拒否、または重複排除されました
- 1 つのエージェントの実行が完了したか、失敗したか、または安全限界に達しました
- 1 つのアカウントがアクティベーション、請求、または保持のマイルストーンに達しました
- 1 つのデータベース操作が境界付きフィンガープリントで完了しました
1 つのテーブルで穀物を混ぜることは避けてください。 1 つの行がリクエストの試行を意味する場合もあれば、すべての再試行にわたる論理リクエストを意味する場合もあり、カウントとレートがあいまいになります。別途使用してください attempt_number または、両方のビューが必要な場合は別の試行イベントを使用します。
操作のライフサイクル全体にわたって正規イベントを構築し、最終結果がわかったときにそれを発行します。
const outcome = {
request_id: requestId,
route_template: "/api/projects/:id/sync",
method: "POST",
team_id: teamId,
release: process.env.APP_RELEASE,
environment: "production",
started_at: new Date().toISOString(),
};
try {
await syncProject();
await telemetry.log("api_request_completed", {
...outcome,
status: "success",
status_code: 200,
latency_ms: Math.round(performance.now() - startedAt),
});
} catch (error) {
await telemetry.log("api_request_completed", {
...outcome,
status: "failed",
status_code: statusFor(error),
error_type: classifyError(error),
latency_ms: Math.round(performance.now() - startedAt),
});
throw error;
}
インストルメンテーション配信では、成功したリクエストが失敗したリクエストに変わってはいけません。制限されたタイムアウトを使用し、配信の失敗を個別に観察し、どの重要なイベントに永続的なキューが必要かを明示的に決定します。
フィールド分類を使用する
有用な標準イベントは通常、次の 6 つのフィールド グループから抽出されます。
| グループ | 例 | なぜ存在するのか |
|---|---|---|
| アイデンティティ | event_id, request_id, run_id |
重複を排除して 1 つの結果を見つける |
| 粒度と結果 | event_name, status, error_type, attempt_number |
カウントされるものを定義する |
| タイミング | timestamp_utc, duration_ms, queue_wait_ms |
ビルドレートとレイテンシの分布 |
| 製品コンテキスト | feature, plan, workflow, route_template |
信頼性をユーザー対応の行動に結びつける |
| 導入コンテキスト | service, environment, region, release |
変更を比較し、回帰を分離する |
| 相関関係 | trace_id, job_id, team_id |
より深い証拠に移動するか、関連イベントに参加します |
グループ化されるフィールドには制御されたカテゴリを使用します。 error_type: "dependency_timeout" 生の例外メッセージよりも信頼性が高くなります。名前には明示的な単位を使用します。 _ms, _bytes, _usd、そして _count。生の URL の代わりに正規化されたルート テンプレートを使用します。
リクエスト ID、アカウント ID、トレース ID などの識別子はカーディナリティが高くなります。これは多くの場合正しいです。グラフの次元が不十分な場合でも、フィルタリングや相関関係には役立ちます。調査上の利点がプライバシー、ストレージ、クエリのコストに見合った場合にのみ保存してください。参照 高カーディナリティのフィールド.
3 つの実用的なイベントの形
API リクエスト イベントでは、分母と結果を一緒に保持する必要があります。
{
"event_name": "api_request_completed",
"request_id": "req_7d91",
"route_template": "/api/projects/:id/sync",
"method": "POST",
"status_code": 503,
"status": "failed",
"error_type": "dependency_timeout",
"latency_ms": 8420,
"release": "2026.07.4",
"schema_version": 2
}
バックグラウンド ジョブ イベントでは、再試行の粒度を明示する必要があります。
{
"event_name": "job_completed",
"job_id": "job_82f1",
"job_name": "sync_billing_account",
"queue_name": "billing",
"status": "failed",
"terminal": true,
"attempt_number": 4,
"queue_wait_ms": 1820,
"duration_ms": 9612,
"error_type": "provider_timeout"
}
エージェント実行イベントは、運用上の結果を機密コンテンツから分離する必要があります。
{
"event_name": "agent_run_completed",
"run_id": "run_28bd",
"workflow": "support_resolution",
"agent_name": "support_agent",
"model": "approved_model_alias",
"status": "success",
"tool_call_count": 3,
"retry_count": 1,
"duration_ms": 4820,
"accepted": true,
"prompt_version": "support-v4"
}
デフォルトでは、生のプロンプト、入力完了、ツール引数、または取得したドキュメントをログに記録しません。結果イベントは、顧客のコンテンツを保持することなく、ボリューム、信頼性、コスト、受け入れに関する質問に答えることができます。
プライバシーの境界を狭く保つ
すべてのフィールドを、クエリ結果、ダッシュボード、エクスポート、サポート業務に表示され得るデータとして扱ってください.イベントの構築時に許可リストを使用します。認可ヘッダー、Cookie、認証情報、接続文字列、リクエストまたはレスポンスの本文、Webhook ペイロード、支払いの詳細、または無制限の顧客コンテンツは含めないでください。
電子メール アドレスよりも内部アカウント識別子を、完全な URL よりもルート テンプレートを、例外テキストよりも制御されたエラー カテゴリを優先します。個人データをハッシュしても自動的に安全になるわけではありません。安定したハッシュは依然としてリンク可能な識別子である可能性があります。文書の所有権、目的、保存、および削除の期待 イベント追跡計画.
複製ではなく相関させる
正規のワイド イベントは、メトリクス、トレース、および詳細な診断ログを補完します。それらを再現する必要はありません。
- メトリクスは、集約されたサービスの健全性とインフラストラクチャのアラートに対して効率的なままです。
- トレースは、スパン全体のタイミングと因果関係を示します。
- 診断ログには、スタック トレースなどのローカルの詳細が保存されます。
- 正規イベントは、完了したアプリケーションまたはビジネスの結果を保存します。
承認されたものを添付する trace_id または、より深い証拠が他の場所にある場合は相関 ID。レスポンダーは、スパン ウォーターフォールまたはスタック トレースをイベントにコピーせずに、失敗した結果行からそのトレースに移動できます。の ログ、メトリック、およびトレースのガイド 境界をより詳細にカバーします。
発売前にスキーマの進化を計画する
イベントに所有者と schema_version。オプションのフィールドを必須にする前に追加してください。数値フィールドを黙って文字列に変更したり、フィールド名を別の意味で再利用したりしないでください。 移行中は、生成元と履歴の参照期間が新しいバージョンに揃うまで、SQLで両方のスキーマバージョンをサポートしてください.
管理されたカテゴリを境界内に保ちます。新しいエラー カテゴリが表示された場合は、ダッシュボード、アラート、または Runbook が変更されるかどうかを確認してください。アプリケーションのアップグレードによってルートまたはワークフローの名前が変更される場合は、実装名とは別に安定した分析名を保存します。
の スキーマ進化ガイド そして データ型とnull可能性 これらのロールアウトの選択肢について説明します。
利便性ではなく決定に基づいたサンプル
まれな失敗、最終的なジョブの結果、請求の変更、セキュリティアクション、または正確な調整に使用されるイベントをサンプリングしないでください。成功した大量のリクエストは、決定論的またはレートベースのサンプリングの候補となる可能性がありますが、下流の分析で合計の推定が必要な場合は、サンプリングの決定と重みが保持されます。
節約されたストレージと失われた質問を比較してください。サンプリングにより、正確なアカウントへの影響のカウントを不可能にしながら、レイテンシーの分布を維持できます。の イベントサンプリングガイド 安全な場合と安全でない場合について説明します。
SQL でイベントを検証します
イベントは、ほとんどのフィールドが含まれている場合ではなく、意図された質問に防御可能な SQL で回答されたときに完了します。非運用環境で、成功、失敗、再試行、タイムアウト、重複配信、NULL フィールド、および遅延到着パスを実行します。ダッシュボードを構築する前に、保存されているスキーマを検査します。
API 結果イベントの場合は、カウントと分母から始めます。
SELECT
route_template,
COUNT(*) AS requests,
SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) AS failures,
100.0 * SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0) AS failure_rate_pct,
approx_percentile_cont(latency_ms, 0.95) AS p95_latency_ms
FROM api_request_completed
WHERE timestamp_utc >= now() - INTERVAL '24 hours'
AND environment = 'production'
GROUP BY route_template
HAVING COUNT(*) >= 20
ORDER BY failure_rate_pct DESC;
レートよりもボリュームを維持し、期間を比較するときに不完全な時間バケットを除外し、再試行が試行であるか論理的な結果であるかを示します。運用上重要になるクエリに対して、決定論的なフィクスチャと期待される結果を保存します。の CI ガイドのインストルメンテーション テスト 契約が逸れないようにする方法を示します。
一度に 1 つのワークフローを移行する
ログ ストリーム全体を置き換えないでください。繰り返し発生する決定を 1 つ選択し、既存のテレメトリの横にその正規イベントを発行し、同じ閉じられた UTC ウィンドウ上で古い回答と新しい回答を二重実行します。再試行処理、ルートの正規化、タイムスタンプ、NULL、および除外の違いを調査します。新しいクエリは、その所有者がセマンティクスを受け入れた後にのみ、ダッシュボードまたはアラートにプロモートされます。
実際のパスは次のとおりです。
- イベントの粒度と決定を定義します。
- ホワイトリストに登録されたフィールド コントラクトを作成します。
- 機器の端末結果。
- 配信とスキーマを確認します。
- フィクスチャを使用してクエリをテストします。
- 二重実行のレポートまたはアラート。
- 冗長なコンシューマのみをリタイアします。
続けて、 構造化されたログ管理ガイド, 構造化イベントとテキスト ログの比較、または完全な 移行ガイド.