Docs 一覧に戻る

opentelemetry-logs-traceability.md

OpenTelemetry におけるログのトレーサビリティ(相関)の実現方法

(データモデル/データパイプライン中心まとめ)

ここでの「ログのトレーサビリティ」は、**ログを「どのサービス(Resource)で」「どの計測スコープ(InstrumentationScope)で」「どの分散トレース(TraceId)・どのスパン(SpanId)に紐づくか」**を、収集〜保管〜検索の全工程で一貫して辿れる状態を指します。


1. 全体像:OpenTelemetry が狙う“ログ相関”の基本設計

OpenTelemetry では、ログは次の 2 つの“軸”で相関(トレーサビリティ)を持てるように設計されています。

  1. エンティティ(実体)軸
  • Resource(例:service.name, host.name, k8s.* など)で「どのサービス/環境のログか」を特定
  • 同じ Resource を持つログは “同じ発生源(エンティティ)” として扱える
  1. リクエスト/処理軸
  • TraceId / SpanId / TraceFlags をログレコード上に持ち、分散トレースと直接リンク
  • これにより UI/検索上で「このトレースに属するログ」「このスパンに属するログ」を引ける

この2軸を OTLP のログデータモデルに標準フィールドとして持たせることが、OpenTelemetry の“ログ相関”の中核です。
(OTLP Logs のトップレベルに trace context のフィールドがある、という位置づけ)


2. データモデル:OTel Logs Data Model の“相関キー”と構造

2.1 3階層のエンベロープ構造

OTLP のログは、概念的に次の構造で束ねられます(実装上は Proto / JSON でもこの階層を踏襲します)。

  • LogsData
    • ResourceLogs(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:リクエスト(トレース)ID
    • SpanId:スパン ID
    • TraceFlags:W3C trace-flags(サンプリング等)
  • 内容
    • Body:メッセージ本文(文字列だけでなく構造化データも可能)
    • Attributes:付随情報(キー/値)
  • 分類
    • SeverityText / SeverityNumber
    • EventName:イベントカテゴリ(同名は同一スキーマ想定)

このうち **TraceId / SpanId / TraceFlags が「分散トレースへリンクするための最小キー」**です。
加えて ResourceInstrumentationScope は「発生源の同定(誰のログか)」に強く効きます。


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 / resource processor 等で service.name や k8s メタデータなどを揃える
  • Resource が揃うと、ログの粒度が増えても “どこから来たか” がブレにくい

(B) LogRecord Attributes を正規化・付与する

  • attributes processor で insert/update/delete/rename などの操作(特にログの「キー名揺れ」対策)

(C) より柔軟な変換(OTTL)

  • transform processor(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 をインデックス化(検索できなければ相関できない)

参考(一次情報中心)