OpenTelemetry におけるログのトレーサビリティ(相関)の実現方法
(データモデル/データパイプライン中心まとめ)
ここでの「ログのトレーサビリティ」は、**ログを「どのサービス(Resource)で」「どの計測スコープ(InstrumentationScope)で」「どの分散トレース(TraceId)・どのスパン(SpanId)に紐づくか」**を、収集〜保管〜検索の全工程で一貫して辿れる状態を指します。
1. 全体像:OpenTelemetry が狙う“ログ相関”の基本設計
OpenTelemetry では、ログは次の 2 つの“軸”で相関(トレーサビリティ)を持てるように設計されています。
- エンティティ(実体)軸
Resource(例:service.name,host.name,k8s.*など)で「どのサービス/環境のログか」を特定- 同じ
Resourceを持つログは “同じ発生源(エンティティ)” として扱える
- リクエスト/処理軸
TraceId/SpanId/TraceFlagsをログレコード上に持ち、分散トレースと直接リンク- これにより UI/検索上で「このトレースに属するログ」「このスパンに属するログ」を引ける
この2軸を OTLP のログデータモデルに標準フィールドとして持たせることが、OpenTelemetry の“ログ相関”の中核です。
(OTLP Logs のトップレベルに trace context のフィールドがある、という位置づけ)
2. データモデル:OTel Logs Data Model の“相関キー”と構造
2.1 3階層のエンベロープ構造
OTLP のログは、概念的に次の構造で束ねられます(実装上は Proto / JSON でもこの階層を踏襲します)。
LogsDataResourceLogs(1つの Resource に紐づくログ束)ScopeLogs(1つの Instrumentation Scope に紐づくログ束)LogRecord(個々のログイベント)
この構造は「どの Resource / どの計測スコープが出したログか」を自然に表現でき、後段のストレージでも “Resource を次元(dimension)” として扱いやすくします。
(OTLP と Proto 定義の安定性・成熟度は OTLP/Proto 側で Stable として整理されています)
2.2 LogRecord の主要フィールド(相関・再現性の観点)
Logs Data Model が定義する LogRecord の主要フィールド(抜粋):
- 時刻
Timestamp:イベント発生時刻(発生源の時計)ObservedTimestamp:観測時刻(Collector 等が観測した時刻)
- トレース相関
TraceId:リクエスト(トレース)IDSpanId:スパン IDTraceFlags:W3C trace-flags(サンプリング等)
- 内容
Body:メッセージ本文(文字列だけでなく構造化データも可能)Attributes:付随情報(キー/値)
- 分類
SeverityText/SeverityNumberEventName:イベントカテゴリ(同名は同一スキーマ想定)
このうち **TraceId / SpanId / TraceFlags が「分散トレースへリンクするための最小キー」**です。
加えて Resource と InstrumentationScope は「発生源の同定(誰のログか)」に強く効きます。
3. “非OTLPのログ”でも相関できるようにする互換ルール
現場では、アプリが OTLP で直接ログを出せない/ファイルログや syslog が先にある、が普通です。
そのため OpenTelemetry には **“既存フォーマットに trace context をどう埋めるか”**の互換ルールが用意されています。
推奨フィールド名(既存フォーマット向け)
trace_id:TraceId(小文字 hex)span_id:SpanId(小文字 hex)trace_flags:W3C traceflags 形式
JSON ならトップレベルに、syslog なら SD-ID opentelemetry の structured data として記録する、といった指針が示されています。
これにより、OTel SDK が出したログでなくても、後段(Collector / Backend)で相関キーを抽出して OTLP LogRecord の
TraceId/SpanIdに載せ替えられる余地ができます。
4. データパイプライン:Collector / OTLP でどう運ぶか
4.1 OTLP は “運搬” の標準(gRPC/HTTP、/v1/logs)
OTLP は、テレメトリ(trace/metric/log)を ソース→中継(Collector)→バックエンドへ届けるためのプロトコル仕様です。
ログについても Stable とされ、Export リクエスト/レスポンスの枠組みで送達されます。
4.2 Collector のパイプライン(Receiver → Processor → Exporter)
Collector は構成ファイルにより、信号(traces / metrics / logs)ごとにパイプラインを作ります。
- receivers:受信(例:
otlpなど) - processors:加工(バッチ、属性の付与/削除、変換)
- exporters:送信(OTLP、各ベンダー backend など)
同じ receiver を複数パイプラインで参照すると fanout される、などの動作もアーキテクチャとして明記されています。
4.3 相関を“壊さない/育てる”ために Processor でやること
(A) Resource を整える(= 発生源の同定を安定化)
resourcedetection/resourceprocessor 等でservice.nameや k8s メタデータなどを揃える- Resource が揃うと、ログの粒度が増えても “どこから来たか” がブレにくい
(B) LogRecord Attributes を正規化・付与する
attributesprocessor で insert/update/delete/rename などの操作(特にログの「キー名揺れ」対策)
(C) より柔軟な変換(OTTL)
transformprocessor(OTTL)で条件付きの属性付与、内容の正規化、resource 変換など- ただし “trace_id / span_id を既存のヘッダから抽出して LogRecord のトップレベルにセットする” は、実装やコンテキストによって制約があるため、Collector の issue/挙動には注意が必要(設計上は OTLP LogRecord にはフィールドがあるが、processor がどこまで触れるかは実装に依存)
5. Baggage を使った“業務キー”の横断的な相関(任意)
TraceId/SpanId は「リクエスト単位」の相関に強い一方、現場では「注文番号」「ロット」「顧客ID」などの業務キーで横断検索したいことがあります。
OpenTelemetry では Baggage(コンテキストに付随する key-value)を使って、
サービス境界を越えて任意のキーを伝播できます(W3C Baggage 仕様に準拠)。
ただし Baggage は HTTP ヘッダ等で流れるため 漏えい・改ざんのリスクがあり、扱いは慎重に。
重要ポイント:
- Baggage は “自動的にログ属性になる” わけではありません
→ どの言語でも、Baggage を読み出してログの Attributes に入れる(あるいは Span Processor で属性化する)などの実装が必要です。 - “外へ出したくない” 境界では Baggage をクリアできる API が要求されています。
6. 実装パターン(データモデル/パイプライン観点の現実解)
パターン1:アプリが OTLP Logs を直接出す(最も素直)
- アプリ内で Logger SDK を利用し、現在の Context(SpanContext)を参照して LogRecord を生成
TraceId/SpanIdが自動で入る(言語実装差はあるが、モデルとしてはこの形)- Collector は主に「Resource の整形」「属性正規化」「バッチ」「エクスポート」に集中できる
向いている:新規システム/マイクロサービス/SDK 導入が可能な環境
パターン2:既存ログ(ファイル/JSON/syslog)→ Collector で OTLP 化
- 既存ログに
trace_id/span_idを埋め込む(または logfmt/JSON のトップレベルに出す) - Collector で受信して OTLP に変換
- 相関キーを “LogRecord のトップレベル TraceId/SpanId に昇格”させたい場合は、Collector の対応状況を確認しつつ設計
- 少なくとも Attributes に保持して backend 側で相関検索できるようにする、という妥協案も現実的
向いている:レガシーアプリ/ライブラリ差し替えが難しい環境
パターン3:TraceContext(traceparent)だけはある → ログへ写す
- HTTP で
traceparentが来る(W3C Trace Context) - アプリ内のログ出力で
trace_id/span_idをログに写す - Collector で OTLP に載せ替え or backend で検索相関
向いている:すでに W3C TraceContext の伝播はあるが、OTel SDK が未導入の環境
7. 最小の Collector ログパイプライン例(相関を壊さず送る)
receivers:
otlp:
protocols:
grpc:
http:
processors:
# 収集効率(順序保証・圧縮効率)を上げる定番
batch:
# ログ属性の正規化・追加(例)
attributes/enrich:
actions:
- key: deployment.environment
value: production
action: insert
exporters:
# 動作確認用(Collector 自身のログ出力)
debug:
# 実運用:OTLP でバックエンドへ
otlphttp:
endpoint: https://YOUR_BACKEND/v1/logs
service:
pipelines:
logs:
receivers: [otlp]
processors: [attributes/enrich, batch]
exporters: [debug, otlphttp]8. 設計チェックリスト(“トレーサビリティが途切れる”典型を潰す)
-
service.name等の Resource 属性が全サービスで揃っている(未設定だと “誰のログか” が崩れる) - ログに
TraceId/SpanIdが入る経路を持っている(OTel SDK 直 or 互換フィールドtrace_id/span_id) - Collector の processors で “相関キーを削っていない”
- “業務キー”を Baggage で流す場合、境界(外部・非信頼)でのクリア/マスキング戦略がある
- backend 側の保存スキーマで
trace_id/span_idと resource attributes をインデックス化(検索できなければ相関できない)
参考(一次情報中心)
- Logs Data Model(LogRecord のフィールド定義)
https://opentelemetry.io/docs/specs/otel/logs/data-model/ - Logs SDK(LogRecord の生成・処理の考え方)
https://opentelemetry.io/docs/specs/otel/logs/sdk/ - OTLP Spec(送達プロトコル、logs は Stable)
https://opentelemetry.io/docs/specs/otlp/ - OTLP Proto(logs/collector/logs の .proto と安定性)
https://github.com/open-telemetry/opentelemetry-proto - Collector パイプライン(Receiver→Processor→Exporter)
https://opentelemetry.io/docs/collector/architecture/ - テレメトリ変換(attributes/transform など)
https://opentelemetry.io/docs/collector/transforming-telemetry/ - 非OTLPログへの Trace Context 記録ルール
https://opentelemetry.io/docs/specs/otel/compatibility/logging_trace_context/ - W3C Trace Context(traceparent/tracestate)
https://www.w3.org/TR/trace-context/ - Baggage(OTel)
https://opentelemetry.io/docs/specs/otel/baggage/api/ - W3C Baggage
https://www.w3.org/TR/baggage/