イベントの記録と追跡
イベントの記録と追跡
1)目的およびフレーム
ログとトレイルは、観測可能性の基礎です。
ログは「何が起こったか」と「どんなコンテキストで」に応答します。
トレースは、分散クエリパスの「どこで、なぜ、ゆっくり/誤って」応答します。
- デフォルトで構造化(JSON);Trace-first:ホットパス上の各ログは'trace_id'/'span_id'にバインドされます。
- 騒音の最低、信号の最高:レベル、サンプリング、反cardinality。
- セキュリティとプライバシー:マスキング、編集、アクセス制御。
- ログとイベントのバージョン管理された図。
2)イベントの分類
宛先ごとにストリームとインデックスを分離:1.テクニカルログ(ランタイム、エラー、ネットワークタイムアウト、リトレイ)。
2.ビジネスイベント(登録、預金、レート、引き出し、KYCステージ)-「お金」パスに沿った製品分析やインシデントに適しています。
3.監査(who/when changed what: configs、 accesses、 flags、 limits)は変更不可のジャーナルです。
4.セキュリティ(認証、特権エスカレーション、制裁/PEPフラグ)。
5.インフラストラクチャ(K8sイベント、オートスケーリング、HPA/VPA、ノード/ディスク/ネットワーク)。
各ストリームについて-保持、インデックス作成、アクセスのための個別のルール。
3)構造ログ(JSON規格)
json
{
"ts": "2025-11-03T14:28:15.123Z",
"level": "ERROR",
"service": "payments-api",
"env": "prod",
"region": "eu-central-1",
"trace_id": "8a4f0c2e9b1f42d7",
"span_id": "c7d1f3a4b8b6e912",
"parent_span_id": "a1b2c3d4e5f60789",
"logger": "withdraw.handler",
"event": "psp_decline",
"msg": "PSP declined transaction",
"http": { "method": "POST", "route": "/withdraw", "status": 502, "latency_ms": 842 },
"user": { "tenant_id": "t_9f2", "user_key": "hash_0a7c", "vip_tier": 3 },
"payment": { "psp": "acme", "amount": 120.50, "currency": "EUR", "idempotency_key": "u123:wd:7845" },
"safe": true, // пройдена проверка на секреты
"version": "1.14.2", // версия сервиса (SemVer)
"build": "sha-1f2a3b4",
"kubernetes": { "pod": "payments-7cbdf", "node": "ip-10-0-2-41" }
}
要件:フラットスキーム+ドメイン別の添付ファイル、必須フィールド('ts、 level、 service、 env、 trace_id、 msg')、数値-数値、文字列ではありません。
4)レベル、cardinalityおよび規模
レベル:'DEBUG'(販売ではない)、'INFO'(ビジネス事実)、'WARN'(異常)、'ERROR'(エラー)、'FATAL'(クラッシュ)。
カーディナリティ:任意のキー/ダイナミックラベルを避けます。「id-in-key」はありません。
サンプリングログ:rate-limit repeating messages;'DEBUG'を有効にするには、スコープと時間内(フィーチャーフラグ)のみを指定します。
Idempotency:消費者による重複イベントを抑制するために'idempotency_key'をログに記録します。
5)プライバシーとセキュリティ
マスクPII/エージェントの秘密(Fluent Bit/Vector):キーマスキングカード('email'、 'card'、 'token'、 'authorization')。
'user_key'をハッシュし、必要なコンテキスト(country、 KYC-level、 VIP-tier)のみを保持します。
個別のストレージ:ウォーム(オンライン検索)とコールド(PIIなしのアーカイブ/ストリップダウンコンテキスト付き)。
監査-追加のみ、WORMストレージ、最小特権の原則にのみアクセス。
6)トレース: 標準とコンテキスト
W3C Trace Context: 'traceparent'/'tracestate'ヘッダ、およびセキュアキーの手荷物(例:'tenant_id'、 'region')。
メトリクスとトレースをリンク:Exemplars-ヒストグラムのサンプリングポイントに'trace_id'を渡します(RCAを加速します)。
サンプリング:基本的なサンプリング1-5%+動的「エラー/遅いp95」問題のクエリの100%まで。
リンク:非同期キュー/サガの場合、リンクは「親」だけではなく「リンク」を通じて広がります。
7)収集とルーティング
エージェント:ログのための流暢なビット/ベクトル;OTLPをOpenTelemetry Collectorにエクスポートします。
コレクター:中央ゲートウェイ(バッチ/変換/フィルタ/ルーティング)。
App → (OTLP logs/traces/metrics) → OTel Collector
→ logs: redact → route(security audit tech biz) → hot index / cold archive
→ traces: tail_sampling(errors p95>threshold) → APM backend
→ metrics: Prometheus exporter (for SLO/alerts)
OTelコレクター(フラグメント):
yaml processors:
batch: {}
attributes:
actions:
- key: env value: prod action: insert filter/logs:
logs:
include:
match_type: strict resource_attributes:
- key: service.name value: payments-api exporters:
otlp/traces: { endpoint: "apm:4317", tls: { insecure: true } }
loki: { endpoint: "http://loki:3100/loki/api/v1/push" }
prometheus: {}
service:
pipelines:
logs: { receivers: [otlp], processors: [attributes,batch], exporters: [loki] }
traces: { receivers: [otlp], processors: [batch], exporters: [otlp/traces] }
metrics: { receivers: [otlp], processors: [batch], exporters: [prometheus] }
8)計装: SDKの例
8.1ノード。js (Pino+OTel)
js import pino from "pino";
import { context, trace } from "@opentelemetry/api";
const logger = pino({ level: process.env.LOG_LEVEL "info" });
function log(info) {
const span = trace.getSpan(context.active());
const base = span? { trace_id: span.spanContext().traceId, span_id: span.spanContext().spanId }: {};
logger.info({...base,...info });
}
// пример log({ event: "deposit.created", amount: 50, currency: "EUR", user: { user_key: "hash_0a7c" } });
8.2 Java (SLF4J+OTel)
java
MDC.put("trace_id", Span.current().getSpanContext().getTraceId());
MDC.put("span_id", Span.current().getSpanContext().getSpanId());
log.info("psp_response status={} latency_ms={}", status, latency);
8.3 Python (structlog+OTel)
python import structlog from opentelemetry import trace log = structlog.get_logger()
def log_json(event, kwargs):
span = trace.get_current_span()
ctx = {}
if span and span.get_span_context().is_valid:
ctx = {"trace_id": span.get_span_context().trace_id, "span_id": span.get_span_context().span_id}
log.msg(event=event, ctx, kwargs)
8.4 NGINX→ヘッダトレーシング
nginx proxy_set_header traceparent $http_traceparent;
proxy_set_header tracestate $http_tracestate;
9)アラートと自動アクションの信号としてログ
誤ったパターン('psp_decline'、 'fraud_flag')が集計され、SLOと相関します。
パターンレートに関するアラート: "5xx by/withdraw> 0。10mあたり5%""、fraud_flagスパイク>ベースの+200%"
自動アクション:ログが'withdrawals_manual_mode=true'の場合、フラグプラットフォームを介してキルスイッチを有効にします。
サンプルルール(擬似式):
rate(count_over_time({service="payments-api", level="ERROR", event="psp_decline"}[5m])) > 5
10)保持、索引付け、貯蔵
ホット:7-14日(運用調査)。
暖かい:30-90日(傾向、RCA)。
Cold: 180-365+(アーカイブ、監査)-圧縮、安価なクラス、おそらく全文検索なし。
インデックス:固定キー('service、 env、 level、 event、 trace_id、 user。tenant_id')、「行のすべて」インデックスの禁止。
イベントサイズ制限(例:≤ 32KB)、トリム/ボトム:「extra in storage is the enemy of MTTR」。
11)監査および不変性
署名/ハッシュ、サーバー時間、'who/what/when/why'、チケットへのリンクを含む別のストリームで監査イベントを作成します。
「DEでボーナスフラグを100%含んだのは誰ですか?」-回答は1-2リクエストである必要があります。
json
{
"ts": "2025-11-03T14:00:00.000Z",
"actor": "alice@company",
"action": "feature_flag.update",
"target": "bonus.enable_vip",
"old": {"rollout": 10},
"new": {"rollout": 100},
"reason": "campaign_2311",
"ticket": "OPS-3481",
"trace_id": "cf12ab.."
}
12)ビジネスイベントとデータモデル
ビジネスイベントは「ログ内のテキスト」ではなく、契約です:- 'event_type'、 'event_id'、 'event_at'、 'actor'、 'subject'、 'amount'、 'currency'、 'status'、 'idempotency_key'。
- 「Outbox」と「at-lost-once」を使用してください。
13) Kubernetesおよびパイプラインログ
Sidecar/DaemonSetエージェントとディスクへのバッファ(ネットワークの中断中)。
ルーティング用のパッドの注釈('log。'、'retentionと入力します。tier')。
K8sコントローラのログを個別に収集します(クラスタインデックス)。
ini
[FILTER]
Name modify
Match
Remove authorization, password, card_number
14)アンチパターン
string logs「必要に応じて」、'trace_id'がない。
ログのPII/秘密、ペイロードダンプ全体。
何百万ものユニークなキー→「爆発」インデックス。
販売中のデバッグ24/7。
監査、セキュリティ、技術者を1つのインデックスに混在させます。
保持ポリシーはなく、バックアップ・リカバリ・テストもありません。
15)実装チェックリスト(0-45日)
0-10日
ゲートウェイ/クライアントでW3C Trace Contextを有効にし、ヘッダを転送します。
アプリケーションログをJSONに変換し、'trace_id'/'span_id'を追加します。
PII/シークレット(エージェントのマスキング)を拒否し、フィールドのリストを承認します。
11-25日
別のストリーム:tech/biz/audit/security/infra、 set retentionおよびACL。
OTel Collector、 tail-sampling errors/slowクエリを有効にします。
ダッシュボード「Log Rate/Error by route」+Jump-to-trace (Exemplars)。
26-45日
コールドログのアーカイブ/リストア(DRテスト)
イベントパターンのアラートとSLOとの相関。
CIのログ図の連結、ビジネスイベントの契約。
16)成熟度の指標
'Trace_id'レクエストカバレッジ≥ 95%です。
JSONログのシェア≥ 99%です。
「jump-to-trace」を介して検出されたインシデントは、15分以下(p50)を解決しました。
ログの0 PIIケース(リークスキャナ)。
すべてのフローで保持が観察されます(監査が自動的に証明されます)。
17)アプリ: ミニスニペット
W3C traceparent生成(擬似)
txt traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
PromQL-ログとSLOの束(例)
high_error_logs = rate(log_events_total{service="payments-api",level="ERROR"}[5m])
5xx_rate = sum(rate(http_requests_total{service="payments-api",status=~"5.."}[5m])) / sum(rate(http_requests_total{service="payments-api"}[5m]))
alert if high_error_logs > 10 and 5xx_rate > 0.005
OpenAPI-相関ヘッダ
yaml components:
parameters:
Traceparent:
name: traceparent in: header required: false schema: { type: string }
18)結論
強力なロギングおよびトレーシング回路は、契約+規律です。構造JSONログ、単一の'trace_id'、安全なPII処理、ストリーム上のルーティングと保持、SLO、アラート、ロールバックとの密接な接続。「テキストのダンプ」からイベント契約とトラックへの移行を行い、生産インシデントの診断が迅速で予測可能で検証可能になります。