Skip to content

✍️ 필사 모드: OpenTelemetry 2026 深掘り — OTLP・セマンティック規約・Collector パイプライン・自動計装、標準化戦争が終わった場所から

日本語
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

プロローグ — 標準化戦争は終わった

2018年の可観測性の風景を思い出してみよう。OpenTracingOpenCensus が並行宇宙で戦っており、トレースデータを送るにはベンダーごとに違う SDK(Datadog, New Relic, Lightstep, Honeycomb …)を入れる必要があった。ライブラリ作者は絶望していた。計装を埋め込みたくても、どの SDK を選ぶか決めねばならない。

2019年、OpenTracing と OpenCensus は OpenTelemetry に合流した。あれから 7 年。

2026年5月の風景は違う。

  • OTLP は事実上唯一の可観測性ワイヤプロトコルだ。Tempo, Jaeger, Honeycomb, Datadog, New Relic, Dynatrace, Grafana Cloud, SigNoz — すべて OTLP を受ける。ベンダー固有プロトコルはレガシー互換のためだけに残る。
  • セマンティック規約 v1 がロックされた。HTTP, リレーショナル DB, メッセージング, RPC, システムメトリクスの属性名はもう変わらない — http.request.method, db.system.name, messaging.system。ダッシュボードを書く人がやっと安心。
  • ログシグナルが GA に。トレースは OTel、ログは別という時代は終わり。
  • Profiles が第四のシグナルとして参入。CNCF インキュベーションを経て 2024 年末から OTLP/profiles のデータが増え始めた。
  • eBPF 自動計装(Beyla, Coroot, OpenTelemetry eBPF Collector)が『SDK なしでトレースが出る』道を開いた。レガシーバイナリ、手を入れられないサービスにトレース一行が現実に。

要するに 標準化戦争は終わった。 いまは OTel を どう デプロイするかの問題だ。本稿は OTLP のワイヤフォーマットから production の Collector パイプライン、言語別自動計装、eBPF 路線のトレードオフまで — 2026年5月時点で実際に動いている形を正確に押さえる。


1章 · 風景 — なぜ OpenTelemetry が勝ったのか

勝敗を決めた決断は三つだ。

  1. ベンダー中立なワイヤフォーマット。OTLP の protobuf スキーマは公開され、gRPC でも HTTP でも動く。どのベンダーも OTLP エンドポイントを開ければその瞬間に OTel 互換になる。ベンダーロックは弱まる — 正確には、ロックが SDK ではなくバックエンド(クエリ言語・UI・価格政策)に移った。
  2. セマンティック規約のロック。HTTP リクエストをどう表現するか(http.request.method, url.full, http.response.status_code)、DB クエリをどう表現するか(db.system.name, db.query.text)が合意された。これがなければ OTel はただのもう一つの SDK だった。
  3. CNCF 卒業。2024 年、OpenTelemetry は Kubernetes に次いで CNCF で二番目に活発なプロジェクトとして卒業。意味は大きい — 一社が抱えていない本物の中立標準だというシグナルだった。

旧い風景 vs 新しい風景

項目2019 年以前2026 年
トレース標準OpenTracing + OpenCensus 並列OpenTelemetry 単一
ワイヤプロトコルベンダーごとOTLP/gRPC + OTLP/HTTP
ライブラリ計装ベンダー SDK に埋め込みOTel API に埋め込み、SDK 差し替え可
ログ別パイプライン(Fluentd 等)OTel シグナル一つ
メトリクスPrometheus 別陣営OTLP + Prometheus 互換
自動計装一部言語のみJava・Python・Node・Go・Ruby・.NET・PHP・Rust
セマンティックベンダー固有http.*, db.*, messaging.* ロック

2章 · OTLP — ワイヤプロトコルが最重要な理由

OpenTelemetry の核は SDK ではなく OTLP だ。OTLP はトレース・メトリクス・ログ・プロファイルデータをバックエンドへ送る protobuf スキーマと転送プロトコル。

2.1 二つのトランスポート

  • OTLP/gRPC — protobuf over HTTP/2。デフォルトポート 4317。最も効率的。サーバ環境の既定値。
  • OTLP/HTTP — protobuf あるいは JSON over HTTP/1.1。デフォルトポート 4318。ブラウザ、Lambda、ファイアウォールが gRPC を塞ぐ環境で使う。

中身(スキーマ)は同じ。トランスポートだけが違う。この分離が重要 — ブラウザから直接 OTLP/HTTP でトレースを送るのが現実的になった。

2.2 ワイヤフォーマットの形(簡略化)

message ExportTraceServiceRequest {
  repeated ResourceSpans resource_spans = 1;
}

message ResourceSpans {
  Resource resource = 1;          // サービス情報 (service.name, deployment.environment...)
  repeated ScopeSpans scope_spans = 2;
}

message ScopeSpans {
  InstrumentationScope scope = 1; // どのライブラリが作ったスパンか
  repeated Span spans = 2;
}

message Span {
  bytes trace_id = 1;
  bytes span_id = 2;
  string name = 5;
  fixed64 start_time_unix_nano = 7;
  fixed64 end_time_unix_nano = 8;
  repeated KeyValue attributes = 9;  // 例: http.request.method = "GET"
  repeated Event events = 11;
  repeated Link links = 13;
  Status status = 15;
}

要は ResourceScopeSpan の三層ツリー。同じサービスの同じライブラリが出したスパンは一束で送られて圧縮率もいい。

2.3 メトリクスとログのワイヤ

同じパターンがメトリクス・ログ・プロファイルにも繰り返される。

  • メトリクス: ResourceMetricsScopeMetricsMetric (Gauge / Sum / Histogram / ExponentialHistogram / Summary)
  • ログ: ResourceLogsScopeLogsLogRecord
  • プロファイル: ResourceProfilesScopeProfilesProfile (pprof 互換スキーマ)

2.4 OTLP はプッシュかプルか

OTLP は プッシュ だ。SDK か Collector がバックエンドに送る。これは Prometheus(プル)との最大の哲学的差。

OTel は Prometheus 互換のため両足を残している。Collector に prometheusreceiver(ターゲットをスクレイプ)と prometheusexporter(Prometheus が取りに来る)の両方がある。現実にはメトリクスだけ Prometheus、トレース・ログは OTLP プッシュのハイブリッドがよくある。


3章 · セマンティック規約 — これが OTel の真の武器である理由

技術的には OTLP が最もかっこいいが、運用者が毎日触るのはセマンティック規約だ

3.1 何がロックされたか

2024 年 9 月から始まった v1 stable のロック作業が、2025〜2026 年にかけて以下を stable に固めた。

  • HTTPhttp.request.method, http.response.status_code, url.path, url.full, url.scheme, server.address, server.port, user_agent.original.
  • データベースdb.system.name, db.namespace, db.query.text, db.collection.name, db.operation.name.
  • メッセージングmessaging.system, messaging.destination.name, messaging.operation.type, messaging.message.id.
  • RPCrpc.system, rpc.service, rpc.method.
  • システムメトリクスsystem.cpu.utilization, system.memory.usage, process.runtime.*.
  • リソースservice.name, service.version, service.instance.id, deployment.environment.name, host.name, os.type, cloud.provider, k8s.pod.name, k8s.namespace.name.

stable にロックされた、というのは — 名前がもう変わらない ということ。ダッシュボード、アラート、クエリ、バックエンド統合 — すべてが安定する。

3.2 なぜロックが重要か

OTel 初期に有名な罠があった。HTTP 属性名が http.method から http.request.method に変わった。デプロイ済みの SDK は全て差し替え、ダッシュボードは全て壊れた。一度ではなく何度か。

v1 ロックはこの痛みを終わらせる。今後の変更は v2 名前空間に入り、v1 は保存される。Kubernetes の API 安定性ポリシーと同じ原理だ。

3.3 セマンティック規約が強制するもの

  • ベンダー間の移動性。同じトレースを Tempo から Honeycomb に動かしてもクエリは同じ。
  • 共用ダッシュボード。Grafana ダッシュボードマーケットプレースの OTel ダッシュボードはセマンティック規約 v1 を前提とする。
  • ライブラリ計装の信頼性。自動計装が出す属性名が標準だから運用者が予測できる。

4章 · トレース・メトリクス・ログ・プロファイル — 四つのシグナルの現状

4.1 トレース

最も成熟したシグナル。OTel 1.0 の核で、2026 年には新規はほぼ入らない。トレースの単位は スパン(span) — 開始・終了時刻、属性、イベント、親スパンを持つ作業の単位。

トレース ID で束ねられて分散システム全体を一回の呼び出しの流れとして見る。traceparent ヘッダ(W3C Trace Context)でサービス境界を越えて文脈が伝播する。

4.2 メトリクス

OTel のメトリクスは Prometheus とモデルが微妙に違う。Prometheus は gauge / counter / histogram / summary、OTel は Counter / UpDownCounter / Gauge / Histogram / ExponentialHistogram / ObservableX に細分化されている。

大きな変化が一つ — ExponentialHistogram が標準入りした。既存の Histogram が事前に決めた bucket boundaries を使うのに対し、ExponentialHistogram は分布に動的に合わせる。P99 のような分位数計算の精度が大きく向上する。

Prometheus 陣営も native histograms で同じ道を行った。両陣営が同じ結論にたどり着いた。

4.3 ログ

2024 年後半に GA 入り。意味は — 別のログパイプラインを構えなくても OTel だけでトレース・メトリクス・ログが全部送れる ということ。

最大の魅力は トレース文脈の自動付与。ログレコードに trace_idspan_id が自動で入り、トレース → ログ、ログ → トレースのジャンプが一クリックで可能。昔はロガーライブラリにコードを埋め込んでいた仕事だ。

ただし、2026 年でも Fluent Bit / Vector は死なない。 OTel のログ receiver は強力だが、コンテナログファイルのテール・パースは Fluent Bit のほうが成熟している。現実の production は『Fluent Bit がファイルを読んで OTLP で Collector に送る』か『Collector の filelogreceiver が直接読む』の二択。

4.4 プロファイル

2024 年 CNCF インキュベーションを経て 第四のシグナル として参入。トレース・メトリクス・ログに続いて継続的プロファイリングが OTel のシグナルに入った。

技術的核心: pprof 互換スキーマ が OTLP に入った。なぜ重要か — Grafana Pyroscope, Polar Signals Parca 等の既存の継続プロファイリングツールが OTLP/profiles を受けるようになれば、一つのパイプラインで四つのシグナルを全部送れる。

2026 年 5 月時点の状況:

  • ワイヤプロトコル(OTLP/profiles): stable に近いベータ。
  • SDK サポート: Go・Python・Java の一部自動計装が profile シグナルを実験的に出力。
  • Collector サポート: otlpreceiverotlpexporter が profiles シグナルを受ける。一部バックエンドは未対応。
  • eBPF: Parca・Pyroscope が eBPF で pprof を生成し OTLP で出力。

要するに GA に近いがまだ完全ではない。始めるときに『profiles を有効化できる SDK・Collector バージョン』を押さえておくとよい。


5章 · Collector アーキテクチャ — 可観測性の nginx

OpenTelemetry Collector は OTel エコシステムで最も重要な単一コンポーネント。その役割は可観測性パイプラインにおける nginx の HTTP トラフィックに対する役割 と同じ — 受信・変換・ルーティング。

5.1 三つのコンポーネントタイプ

+-------------+      +-------------+      +-------------+
|  Receivers  | ---> | Processors  | ---> |  Exporters  |
+-------------+      +-------------+      +-------------+
   otlp                batch                otlp
   prometheus          memory_limiter        prometheusremotewrite
   filelog             attributes            elasticsearch
   jaeger              k8sattributes         loki
   zipkin              tail_sampling         tempo
   kafka               filter                kafka
                       transform
  • Receivers — データを受けるアダプタ。OTLP が既定だが、Prometheus スクレイプ・Jaeger・Zipkin・Fluent Forward・Kafka・SQS 等、何でも受けられる。
  • Processors — 受けたデータを変換・フィルタ・強化する。batch はほぼ必須、memory_limiter は安全網、k8sattributes は Kubernetes メタデータの自動付与、tail_sampling はサンプリング判定をトレース完了後まで遅らせる。
  • Exporters — バックエンドに送る。OTLP が既定だがバックエンド別の専用エクスポータも多い。

5.2 Core vs Contrib

Collector のディストリビューションは二つに分かれる。

  • otelcol (core) — 最も核となるコンポーネントのみ。セキュリティ監査を受けやすくバイナリが小さい。
  • otelcol-contrib (contrib) — 全てのコミュニティコンポーネント。99% の production は contrib を使う。

推奨: 最初は contrib で始める。運用が安定したら OpenTelemetry Collector Builder (ocb) で必要なコンポーネントだけを選んでカスタムビルド。

5.3 パイプラインの概念

Collector の設定は pipelines で束ねられる。シグナルタイプ別に別のパイプライン。

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, k8sattributes, batch]
      exporters: [otlphttp/tempo]
    metrics:
      receivers: [otlp, prometheus]
      processors: [memory_limiter, batch]
      exporters: [prometheusremotewrite]
    logs:
      receivers: [otlp, filelog]
      processors: [memory_limiter, k8sattributes, batch]
      exporters: [otlphttp/loki]

同じ receiver を複数パイプラインで共有可能、fan-out・fan-in も自由。


6章 · Production Collector 設定 — sidecar → gateway → backend

実際の production パターンで最も多い形は 二段階層 だ。

+----------------+   OTLP   +-----------+   OTLP    +-----------+
| App + SDK      | -------> | Collector |---------->| Collector |
| (Pod sidecar)  |          | (sidecar) |           | (gateway) |
+----------------+          +-----------+           +-----------+
                                                          |
                                                          | OTLP / proprietary
                                                          v
                                                 +------------------+
                                                 | Tempo / Jaeger / |
                                                 | Honeycomb / etc. |
                                                 +------------------+
  • sidecar Collector (DaemonSet または Pod サイドカー) — ローカルで素早く受けて batch・リトライ。アプリは OTLP を送って素早くレスポンスをもらって自分の仕事に戻る。
  • gateway Collector (Deployment) — クラスタ単位で集約し tail sampling・メタデータ強化・ルーティング・複数バックエンドへの fan-out。
  • backend — Tempo / Jaeger / SigNoz / Honeycomb / Datadog。OTLP を受ける場所。

6.1 sidecar / agent Collector 設定例

# otelcol-agent-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318
  prometheus:
    config:
      scrape_configs:
        - job_name: 'self-metrics'
          scrape_interval: 30s
          static_configs:
            - targets: ['localhost:8888']

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 400
    spike_limit_mib: 100
  k8sattributes:
    auth_type: serviceAccount
    passthrough: false
    extract:
      metadata:
        - k8s.pod.name
        - k8s.namespace.name
        - k8s.node.name
        - k8s.deployment.name
        - k8s.cluster.uid
  batch:
    timeout: 200ms
    send_batch_size: 8192

exporters:
  otlp/gateway:
    endpoint: otelcol-gateway.observability.svc.cluster.local:4317
    tls:
      insecure: true
    retry_on_failure:
      enabled: true
      initial_interval: 5s
      max_interval: 30s
    sending_queue:
      enabled: true
      num_consumers: 4
      queue_size: 5000

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, k8sattributes, batch]
      exporters: [otlp/gateway]
    metrics:
      receivers: [otlp, prometheus]
      processors: [memory_limiter, k8sattributes, batch]
      exporters: [otlp/gateway]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, k8sattributes, batch]
      exporters: [otlp/gateway]

6.2 gateway Collector 設定(tail sampling 込み)

gateway は通常トレース全体を受けて判断する — どのトレースを保存するか、どこに送るか。

# otelcol-gateway-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 4000
    spike_limit_mib: 800
  tail_sampling:
    decision_wait: 10s
    num_traces: 100000
    expected_new_traces_per_sec: 1000
    policies:
      - name: errors
        type: status_code
        status_code: { status_codes: [ERROR] }
      - name: slow-requests
        type: latency
        latency: { threshold_ms: 1000 }
      - name: sample-10pct
        type: probabilistic
        probabilistic: { sampling_percentage: 10 }
  batch:
    timeout: 1s
    send_batch_size: 16384

exporters:
  otlphttp/tempo:
    endpoint: http://tempo-distributor.monitoring.svc.cluster.local:4318
  prometheusremotewrite:
    endpoint: http://mimir-distributor.monitoring.svc.cluster.local/api/v1/push
  otlphttp/loki:
    endpoint: http://loki-distributor.monitoring.svc.cluster.local:3100/otlp

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, tail_sampling, batch]
      exporters: [otlphttp/tempo]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [prometheusremotewrite]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlphttp/loki]

6.3 実戦運用のコツ

  • memory_limiter は最初のプロセッサに。メモリが暴走すると他のすべてのプロセッサは無意味。
  • tail sampling は gateway だけに。agent レベルでやるとトレースが分断される。
  • k8sattributes は agent に置くのが定石。gateway には pod 情報が届かないことがある。
  • batch のサイズと timeout はバックエンド容量に合わせて調整。小さすぎると RPS が爆発、大きすぎると latency が伸びる。
  • Collector 自体のメトリクスをスクレイプせよ:8888/metricsotelcol_processor_dropped_spans 等がある。

7章 · 言語別自動計装 — どこまで自動でできるか

OpenTelemetry の最大の魅力の一つが 自動計装(auto-instrumentation)。コードを一行も触らずに HTTP ハンドラ・DB ドライバ・gRPC クライアントのスパンが出る。

言語別の成熟度は大きく違う。

7.1 Java — 最強

opentelemetry-javaagent.jar が事実上の業界標準。JVM の -javaagent メカニズムでバイトコードを実行時に書き換え、100 以上のライブラリ(Spring, Hibernate, Apache HttpClient, Kafka, JDBC, Servlet, Reactor, gRPC, AWS SDK …)を自動計装する。

java -javaagent:opentelemetry-javaagent.jar \
     -Dotel.service.name=order-service \
     -Dotel.exporter.otlp.endpoint=http://otelcol-agent:4317 \
     -Dotel.exporter.otlp.protocol=grpc \
     -Dotel.resource.attributes=deployment.environment.name=prod \
     -jar app.jar

これで終わり。コード変更 0 行。Spring Boot コントローラ、全ての JDBC 呼び出し、Kafka producer・consumer のスパンが自動で出る。トレース文脈の伝播も自動。

Java が best-in-class な理由 — JVM が実行時のバイトコード操作に最も自由で、OTel Java チームが最大で、Datadog Java agent のノウハウがそのまま OTel に合流した。

7.2 Python — opentelemetry-instrument

Python は opentelemetry-instrument ランチャと opentelemetry-distro パッケージで自動計装する。monkey-patching でライブラリを包む方式。

pip install opentelemetry-distro opentelemetry-exporter-otlp \
            opentelemetry-instrumentation-flask \
            opentelemetry-instrumentation-requests \
            opentelemetry-instrumentation-psycopg2

opentelemetry-bootstrap -a install   # 入っているライブラリを自動検出

OTEL_SERVICE_NAME=order-service \
OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol-agent:4317 \
OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=prod \
opentelemetry-instrument python app.py

対応ライブラリは Flask, Django, FastAPI, Starlette, requests, urllib3, httpx, psycopg2, asyncpg, SQLAlchemy, Redis, pymongo, celery, kafka-python, boto3 など。Java ほどではないが、日常的なライブラリはほぼ網羅される。

7.3 Node.js — require hook ベース

Node は @opentelemetry/auto-instrumentations-node で require フックを掛けて自動計装する。

// tracing.js — アプリのエントリポイントより先にロードされる必要がある
const { NodeSDK } = require('@opentelemetry/sdk-node')
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc')

const sdk = new NodeSDK({
  serviceName: 'order-service',
  traceExporter: new OTLPTraceExporter({
    url: 'http://otelcol-agent:4317',
  }),
  instrumentations: [getNodeAutoInstrumentations()],
})

sdk.start()

実行:

node --require ./tracing.js app.js

ESM では --import フラグと hook loader が必要(Node 20.6+ の register() API)。CommonJS 環境のほうが自動計装はまだスムーズ。

対応ライブラリ: Express, Koa, Fastify, Hapi, http, https, pg, mysql, redis, mongoose, ioredis, kafka.js, AWS SDK, GraphQL など。

7.4 Go — コンパイル時計装の革命

Go は長らく『OTel の弱点』だった。Go は monkey-patching が難しく、vtable がないので実行時インターセプトが綺麗でない。だから Go は長らく 手動計装のみ だった。

2024〜2025 年に二つの道が開いた。

道 1: go build 時にコード注入 — otel-go-instrumentation

go install github.com/open-telemetry/opentelemetry-go-instrumentation/cli@latest

# ビルド時に自動計装を注入
otel-instrument go build -o app ./...

ビルドツールが標準ライブラリと人気パッケージ(net/http, gRPC, database/sql 等)の呼び出しを包むラッパを自動生成して注入する。ソース変更 0 行。

道 2: eBPF で外から — Beyla

ビルド時注入すらしない。Beyla が別プロセスで立ち上がり、eBPF でカーネルが見るシステムコール・ソケット越しにトレースを作る。この道は 8 章で詳しく。

7.5 .NET, Ruby, PHP, Rust

  • .NETOpenTelemetry.AutoInstrumentation NuGet パッケージ。CoreCLR profiler API で IL を書き換え。Java に次ぐ成熟度。
  • Rubyopentelemetry-instrumentation-all gem。monkey-patch ベース。Rails, Sinatra, Rack 等。
  • PHPopen-telemetry/opentelemetry-auto-laravel 等。OPcache 拡張が要るケースあり。
  • Rust — 自動計装はほぼない。tracing クレートの OTel アダプタで手動計装が標準。

7.6 自動計装の限界

自動計装は HTTP・DB・メッセージ・RPC の境界しか見ない。ビジネスロジックの意味ある単位 — 『注文作成』『決済検証』『在庫減算』 — は見えない。

production OTel の正解は 自動計装 + 手で書くビジネススパン だ。自動計装がインフラ境界を全部押さえ、手で書くスパンがビジネスの意味を加える。


8章 · eBPF 自動計装 — SDK なしでトレースが出る道

2024〜2025 年の最大の変化の一つ。eBPF で SDK を入れずに トレースが作られる。

8.1 仕組み

eBPF 自動計装ツールは別プロセスで立ち上がり、カーネルのシステムコール・ソケットイベントをフックする。HTTP リクエスト、gRPC 呼び出し、DB 接続を直接観察する。

  • アプリは普通のバイナリ。SDK も javaagent もない。
  • eBPF プログラムが acceptconnectreadwrite 等をフックしてパケットをデコード。
  • デコードしたトランザクションを OTLP で Collector に送る。

8.2 ツールたち

  • Grafana Beyla — Grafana Labs のオープンソース。Go・Java・Node・Python・Rust を同じ方式で見る。トレース・メトリクス両方を出力。2024 年 GA。
  • Coroot — Beyla の上にフルスタック可観測性 — eBPF で集めて自前 UI を持つ。OTel 互換。
  • OpenTelemetry eBPF Collector — OTel 公式陣営。元は Splunk が作って OTel に寄贈。システムメトリクスとネットワーク段のトレースを見る。
  • Pixie (Pixie Labs) — Kubernetes 専用。eBPF + 自前クエリ言語。OTel 出力可能。
  • Cilium Hubble — ネットワーク層に集中。Cilium の可観測性コンポーネント。

8.3 eBPF 路線の強み

  • SDK 0 行。レガシーバイナリ、手を入れられない第三者サービスにトレースが可能。
  • 計装漏れリスク 0。ライブラリのバージョンが OTel と合わなくても見える。
  • 言語非依存。Beyla 一つで Go・Java・Node・Python・Rust のトレースが同じ形で出る。
  • 運用圧が低い。アプリを再デプロイしなくても適用。

8.4 eBPF 路線の限界

  • 分散トレース文脈の伝播が難しい。HTTP ヘッダの traceparent は eBPF が読めるが、アプリがそれを受けて内部の関数呼び出しまで繋ぐのは不可。結果 — サービス単位のトレースはよく出るが、関数単位のグラフは薄い。
  • 暗号化トラフィック。TLS の中の HTTP/2 を見るには uprobes でライブラリ関数をフックする必要。最近のツールはこれをサポートするが互換マトリクスは狭い。
  • カーネル権限が必要。Pod が CAP_BPF または privileged を要する。セキュリティポリシーで塞がれることがある。
  • ビジネスロジック 0。『注文作成』のようなドメインの意味は捕まえられない。

8.5 eBPF + SDK ハイブリッド

production の正解は eBPF + SDK ハイブリッド だ。

  • eBPF — インフラの絵(サービス間呼び出し、DB クエリ、外部 API 呼び出し、ネットワーク latency)。
  • SDK — ビジネスの意味(ドメインスパン、カスタムメトリクス、ビジネスログ)。

二つのデータを同じ trace_id で束ねるのは — 難しい。現実には『eBPF トレースグラフ + SDK トレースグラフ』が別々に並ぶことが多い。2026 年 5 月時点でこの部分が最も活発に改善されている。


9章 · リソース検出 (Resource Detection)

OTel シグナルの全データは Resource に結び付けて送信される。『service.name=order-service, deployment.environment.name=prod, host.name=node-01, k8s.pod.name=order-69b』のようなメタデータ。

これを手で全部入れることもできるが、OTel SDK と Collector には 自動リソース検出器 がある。

9.1 検出器の種類

  • 環境変数OTEL_RESOURCE_ATTRIBUTES=service.name=order,deployment.environment.name=prod.
  • プロセス — pid, command, runtime version.
  • ホスト — hostname, OS, architecture.
  • コンテナ — container.id (cgroup から抽出).
  • KubernetesdownwardAPI で env vars 注入、または Collector の k8sattributes プロセッサが pod IP から強化。
  • クラウド — AWS EC2/ECS/EKS/Lambda, GCP GCE/GKE/Cloud Run, Azure VM/AKS の IMDS を叩いてインスタンスメタデータを検出。

9.2 優先順位

OTel 仕様は優先順位を定める — 環境変数より SDK 既定値、それより明示的なコード設定が強い。クラウド検出器は SDK 起動時に自動で走る。

9.3 production パターン

env:
  - name: OTEL_SERVICE_NAME
    value: order-service
  - name: OTEL_RESOURCE_ATTRIBUTES
    value: "deployment.environment.name=prod,service.version=$VERSION"
  - name: POD_NAME
    valueFrom:
      fieldRef:
        fieldPath: metadata.name
  - name: NODE_NAME
    valueFrom:
      fieldRef:
        fieldPath: spec.nodeName
  - name: OTEL_RESOURCE_ATTRIBUTES_OTHER
    value: "k8s.pod.name=$POD_NAME,k8s.node.name=$NODE_NAME"

あるいは Collector の k8sattributes プロセッサに任せるほうが綺麗。SDK 側は service.name だけ押さえ、残りは Collector が pod IP → API server 照会で自動強化。


10章 · ベンダー SDK から OTel SDK へ — 移行の話

2024〜2025 年に最もよく見た移行パターン。

10.1 シナリオ — Datadog dd-trace から OTel へ

すでに Datadog dd-trace でトレースを送っているコードベース。OTel に行きたい。二つの道。

道 1: dd-trace の OTel API 互換モード

dd-trace 自体が OTel API を受けるモードを持つ。コードは OTel API で書き、dd-trace がワイヤフォーマットを処理。

[コード: OTel API] -> [dd-trace agent: OTel API を受ける] -> [Datadog バックエンド: dd-trace フォーマット]

利点: 段階移行。コードは OTel API に先に切り替えておき、バックエンドはゆっくり。 欠点: dd-trace を最終的に剥がさないと意味が薄い。

道 2: OTel SDK 直出力

[コード: OTel API] -> [OTel SDK] -> [OTLP] -> [OTel Collector] -> [Datadog の OTLP エンドポイント、またはバックエンド切替]

利点: 本物の OTel。バックエンド切替が自由。 欠点: 一気に動く必要。dd-trace の一部自動計装が OTel にまだない場合、ギャップが出る。

10.2 段階移行の順序

  1. OTel Collector をまず立てる。dd-trace agent と並行運用。
  2. 新サービスから OTel SDK。dd-trace は新サービスには追加しない。
  3. トレース → メトリクス → ログの順で移行。トレースが最もスムーズで、ログが最もダッシュボード互換が難しい。
  4. ダッシュボード書き直し。セマンティック規約が違う(http.status_code vs http.response.status_code)。一気に全部変えず、新ダッシュボードから。
  5. dd-trace agent 撤去。全サービスが OTel SDK に移ってから。

10.3 正直なトレードオフ

OTel SDK が全ての面でベンダー agent より優れているわけではない。

項目OTel SDKベンダー SDK(例: dd-trace)
自動計装の幅良い(Java best-in-class)非常に広い(長年の蓄積)
ランタイムオーバーヘッド一般にやや重い長年チューニングされ軽いことも
バックエンド自由度非常に大きい一ベンダーに縛られる
セマンティック一貫性標準セマンティック規約ベンダー固有名
診断・サポートコミュニティベンダー SRE サポート
AI/ML ワークフロー新興(OTel GenAI 規約)一部ベンダーが先行

要するに OTel はロックを解く代わりに少しのランタイムコストを払う。受け入れられるか — 答えはたいてい『Yes』。バックエンド自由度の価値が SDK 微チューニングを大きく上回る。


11章 · GenAI セマンティック規約 — 次にロックされる領域

2025〜2026 年の OTel 陣営で最も活発な作業領域。LLM 呼び出しを追跡するためのセマンティック規約がロック直前まで来ている。

主な属性(ベータ、近々 stable 予定)。

  • gen_ai.systemopenai, anthropic, google, ollama
  • gen_ai.request.modelclaude-3.5-sonnet, gpt-4o
  • gen_ai.usage.input_tokens / gen_ai.usage.output_tokens — コスト・レート制限の追跡。
  • gen_ai.response.finish_reasonsstop, length, tool_calls
  • gen_ai.operation.namechat, tool_call, embedding, text_completion.
  • イベント — メッセージ単位の入出力(オプション、コスト・プライバシーのトレードオフ)。

LangChain, LlamaIndex, OpenLLMetry, Arize Phoenix などがこの規約に追従する。LLM ワークフローのコスト・latency・失敗率を標準化された形で見られる。次の四半期か二つ以内に v1 stable へロックされる可能性が高い。


12章 · よくある間違いとアンチパターン

production でよく見る間違い。

12.1 SDK が直接バックエンドへ送る

アプリ SDK ----(OTLP)----> Datadog / Honeycomb

小さな環境では動く。大きな環境で問題 — アプリ再デプロイなしにバックエンドポリシー(サンプリング、ルーティング、強化)を変えられない。必ず Collector を一段挟む。

12.2 head sampling でエラートレースを失う

SDK が 1% サンプリングすると、エラートレースの 99% も一緒に消える。エラーは無条件で保存 しなければならないので tail sampling(Collector で)を使う。

12.3 trace ID・span ID を手で作る

直接 16 バイト UUID を作って trace_id に詰めるコードを見たが、標準トレース文脈伝播と合わない。OTel API の getCurrentSpan().spanContext() を使え。

12.4 リクエストごとに新しい Tracer を作る

// 悪い例
function handler(req) {
  const tracer = trace.getTracer('app')  // 毎回新規取得に見える
  tracer.startSpan(...)
}

getTracer はキャッシュされるが、モジュール最上位で一度受け取るほうが意図表現が綺麗。

12.5 batch なしの OTLP 直出力

batch プロセッサなしで送ると RPS 分の小さなリクエストが出る。batch プロセッサは事実上必須。

12.6 PII が属性に入る

http.request.bodyuser.email をそのまま属性に詰めると可観測性バックエンドに平文 PII が溜まる。attributes プロセッサでマスクするか抜く。

12.7 ExponentialHistogram を使わず固定 bucket で P99

既定の Histogram が 5ms / 10ms / 50ms / 100ms / 500ms のような固定 bucket を使うと P99 計算が不正確。ExponentialHistogram を既定に。

12.8 Collector を単一インスタンスで SPOF

agent は DaemonSet, gateway は HPA。常に複数インスタンス。 gateway が落ちるとその時刻の全シグナルが消える。


エピローグ — 標準が敷かれた場所で何をするか

OpenTelemetry は 2026 年 5 月時点で 標準化戦争に勝った位置 にいる。ただし『OTel を使うか』はもはや興味深い問いではない。興味深い問いはこれ。

  • どれだけ上手く敷いたか。agent + gateway 二段か単一インスタンスか。tail sampling はあるか。memory_limiter が最初のプロセッサか。
  • セマンティック規約を守っているか。自動計装だけでなくビジネススパンにもセマンティック規約を適用しているか。
  • 自動計装と手計装のバランス。インフラ境界は自動、ビジネスの意味は手で。
  • eBPF をどこに使うか。レガシー・第三者にだけか、それとも SDK 側が全然動かない環境のメインか。
  • profiles シグナルを受け取る準備。バックエンドと SDK のバージョンが受けられるか。

導入チェックリスト

  • Collector を agent + gateway の二段に構成したか。
  • memory_limiter が全パイプラインの最初のプロセッサか。
  • tail sampling が gateway にあり、エラーと遅いリクエストが無条件で保存されるか。
  • k8sattributes プロセッサが agent で動いているか。
  • batch プロセッサが全パイプラインに入っているか。
  • 自動計装が入った言語は javaagent / opentelemetry-instrument / require hook / コンパイル時注入のいずれで動いているか。
  • ビジネススパンにセマンティック規約が適用されているか。
  • PII が属性に入らないように attributes プロセッサがマスクしているか。
  • Collector の self-metrics をスクレイプしているか(otelcol_processor_dropped_spans 等)。
  • ExponentialHistogram を既定で使っているか。
  • バックエンドが GenAI セマンティック規約を受ける準備があるか。

アンチパターン整理

  1. SDK が直接バックエンドへ — Collector を一段挟め。
  2. head sampling のみ — エラートレースを失う。tail sampling を追加。
  3. batch プロセッサなしで OTLP — RPS 分の小さなリクエスト。
  4. memory_limiter を最後に — メモリが暴走すると意味なし。最初に。
  5. PII がそのまま属性に — attributes プロセッサでマスク。
  6. 自動計装だけ信じてビジネススパン 0 行 — インフラ境界しか見えない。
  7. Collector を単一インスタンス — SPOF。複数インスタンス必須。
  8. セマンティック規約を無視したカスタム属性 — ダッシュボード互換が壊れる。
  9. トレースだけ送ってメトリクス・ログは別パイプライン — OTel シグナル三つを一つのパイプラインで束ねたとき最大の価値。
  10. profiles シグナルを受けるバックエンドがないのに SDK で有効化 — データがどこにも行かない。

次回予告

次回候補: Collector 運用の深い話 — パイプライン負荷・ドロップ・メトリクスカーディナリティの罠, OTel Profiles 実戦 — eBPF で Go バイナリの hotspot を捕まえる, GenAI セマンティック規約で LLM コスト・latency・失敗率を単一ダッシュボードで見る方法.


参考 / References

현재 단락 (1/457)

2018年の可観測性の風景を思い出してみよう。**OpenTracing** と **OpenCensus** が並行宇宙で戦っており、トレースデータを送るにはベンダーごとに違う SDK(Datado...

작성 글자: 0원문 글자: 22,955작성 단락: 0/457