👌

Rust から Datadog にトレースを送る方法の整理(dd-trace-rs 登場を踏まえて)

に公開

2025年12月、Datadog 公式の Rust トレーシングライブラリ dd-trace-rs(クレート名 datadog-opentelemetry)の v0.2.0 がリリースされ、"datadog-opentelemetry is stable enough for general use!" とアナウンスされました。

Rust から Datadog にトレースを送る方法は複数あり、それぞれトレードオフが異なります。結論としては、ベンダー非依存性を重視するなら OpenTelemetry 標準の OTLP で Datadog Agent に送る方式OTLP 送信、Datadog 固有の運用機能を活用したいなら dd-trace-rs が候補になります。本記事ではその判断材料として、各方式の違いを整理します。

Rust の前提と他言語との比較

他の言語では、Datadog 公式のトレーサー(dd-trace-rb、dd-trace-js 等)が計装から送信まで一貫して担います。Go の dd-trace-go はランタイムでの自動計装ができないためコード変更が必要ですが[1]、それでも計装と送信は同じライブラリが担います。

Rust では事情が異なり、計装と送信を別々のクレートで組み立てます。
計装(スパンの生成)には tracing クレートがよく使われ、生成されたスパンを tracing-opentelemetry で OpenTelemetry SDK に渡します(OpenTelemetry API で直接計装する方法もあります)。

送信側は、OpenTelemetry SDK(opentelemetry_sdk)のパイプラインに組み込むクレートが担います。dd-trace-rs もその 1 つですが、他の言語の dd-trace シリーズとは異なり計装機能は持ちません。

本記事では、このうち送信方式の違いにフォーカスします。

送信の選択肢

以降では Datadog Agent を経由する構成を扱います[2]。

2021年3月、opentelemetry-datadog が初版リリースされ、OTel SDK のスパンをアプリ内で Datadog ネイティブ形式(msgpack)に変換して Datadog Agent に送る最初の手段になりました。

2022年4月、Datadog Agent 7.35.0 でトレースの OTLP 受信が安定サポートとなり、opentelemetry-otlp を使って OTLP で Datadog Agent に送り、Datadog Agent 側で変換させる方法が加わりました(以下、OTLP 送信と呼びます)。

2025年12月、dd-trace-rs の v0.2.0 が stable としてリリースされ、現在の 3 択になっています。

  • dd-trace-rs — アプリ内で変換、Datadog ネイティブ形式で Datadog Agent に送信(Datadog 公式)
  • opentelemetry-datadog — アプリ内で変換、Datadog ネイティブ形式で Datadog Agent に送信(OTel コミュニティ)
  • OTLP 送信 — 変換せず OTLP で Datadog Agent に送信、Datadog Agent が変換(OTel 標準)

次章では、この 3 つの変換品質と運用機能の違いを比較します。

3 つの方式の比較

変換品質

OTel のスパンには Datadog APM の UI が期待するフィールド(operation_name、resource、type 等)が直接存在しないため、OTel の属性から Datadog 形式への変換がどの送信方式でも必要です[3]。

OTLP 送信では Datadog Agent が変換を行うため、Datadog Agent の変換ロジック(pkg/trace/transform/transform.go)がそのまま適用されます。dd-trace-rs はこのロジックをアプリ内に移植したもので、変換コードにも "This code has been ported from the otlp receiver in the datadog agent." とコメントされています。Semantic Conventions 属性と SpanKind の組み合わせから、以下のように変換されます。

  • HTTP スパン → operation_name = "http.server.request", resource = "GET /api/users"
  • DB スパン → operation_name = "{db_system}.query", resource = "SELECT * FROM users"

Datadog はこのルールを V2 マッピングと呼んでおり、Datadog Agent v7.66+ でデフォルト有効になっています(参考 — Migrate to New Operation Name Mappings)。

dd-trace-rs opentelemetry-datadog OTLP 送信
変換ルール V2(Datadog Agent と同一) 独自実装(V2 非対応) V2(Datadog Agent が適用)
変換の実行場所 アプリ内 アプリ内 Datadog Agent 内

opentelemetry-datadog は V2 ロジックを持っておらず、Datadog UI での表示が期待と異なる場合があります。ソースコード内にも Datadog Agent の変換に追従すべきという todo コメントが残っています。dd-trace-rs が登場したいま、opentelemetry-datadog は新規採用の第一候補としては位置づけにくくなっています。

dd-trace-rs と OTLP 送信の間では、UI 上の表示品質に大きな差はありません(ただし実装追従のタイミングにより差異が生じる可能性はあります)。

運用機能

変換品質では dd-trace-rs と OTLP 送信に大きな差がないため、この 2 つの差分は主に運用機能にあります。OTLP 送信はベンダー非依存で Datadog 固有のクレートに依存しません。dd-trace-rs は以下の Datadog 固有機能を提供します。opentelemetry-datadog はこれらの機能を持ちません。

1. トレース単位のバッチ送信

OTel SDK の標準バッチ処理はスパンを到着順にまとめて送ります。dd-trace-rs はトレース ID ごとにスパンを集約し、1 つのトレースに属するスパンをまとめて送ります。root スパンがチャンクの先頭に配置されるため、Datadog Agent 側でのトレース再構成が不要になります。

2. Datadog Agent との協調サンプリング

dd-trace-rs は Datadog Agent とサンプリングレートを交渉します。Datadog Agent がサービスごとのサンプリングレートをフィードバックし、アプリ側がそれに従う仕組みです。OTel SDK 標準のサンプラーはこの仕組みに参加できないため、Datadog Agent 側でサンプリングするか、アプリ側で固定レートを設定する必要があります。

3. APM stats のクライアントサイド計算

Datadog APM はトレースデータとは別に、サービスごとのヒット数・エラー率・レイテンシ分布等の統計情報(APM stats)を集計します。通常は Datadog Agent がこの計算を行いますが、dd-trace-rs はアプリ内で計算して Datadog Agent に送ることができます。トラフィックが多いサービスでは Datadog Agent の CPU 負荷を軽減できます。

4. Remote Configuration

Datadog のリモート設定に対応しており、再デプロイなしでサンプリングレートの変更等が可能です。

5. Datadog Propagator のデフォルト設定

分散トレーシングでは、サービス間の HTTP 通信時にトレース ID をヘッダーに埋め込んで伝搬します。伝搬形式には W3C Trace Context(traceparent ヘッダー、OTel 標準)と Datadog 形式(x-datadog-trace-id 等のヘッダー)があり、dd-trace-rs は初期化時に両方に対応する propagator を自動設定します。

dd-trace-rs は Datadog 公式のライブラリであり、上記の機能に限らず、Datadog のアップデートに合わせて今後も機能が拡張されていくことが予想されます。

依存関係と保守主体

ここまでは主に変換の品質と運用機能の観点で比較してきましたが、実務では依存関係やメンテナンス主体、つまりサプライチェーンリスクも判断材料になります。各選択肢は依存クレートの数や提供元が異なります。

dd-trace-rs は依存ツリーが最も深くなります。libdatadog 由来の内部クレートが直接依存に含まれ、これらがさらに別の libdd クレートに依存します。加えて、TLS の依存先にビルド時に C コンパイラを必要とするクレートを含んでいます。依存先の増加とあわせて、保守主体が Datadog 側に寄る点は認識しておくとよいでしょう。

opentelemetry-datadog は純粋な Rust で構成され、ネイティブコードの依存がありません。msgpack エンコードの rmp クレート等が加わりますが、依存は浅いです。OTel org が publish しています。

OTLP 送信が最も依存が少なく、OTel 公式クレートと tokio-rs(tonic/prost)や reqwest 等の広く使われたエコシステムクレートのみで構成されます。ベンダー固有のコードを含みません。

dd-trace-rs opentelemetry-datadog OTLP 送信
OTel SDK 以外の直接依存[4] 22 7 2(+ feature で tonic や reqwest)
ビルド時に C コンパイラが必要 あり なし なし
保守主体 Datadog OTel org OTel org

まとめ

Rust から Datadog にトレースを送る方法として、dd-trace-rs、OTLP 送信、opentelemetry-datadog を比較しました。

dd-trace-rs と OTLP 送信は同じ V2 の変換ルールに基づいており、UI 表示の観点では差が小さいです。主な判断軸は Datadog 固有の運用機能をどこまで重視するかであり、ベンダー非依存性を重視するなら OTLP 送信、Datadog 固有の運用機能を活用したいなら dd-trace-rs が候補になります。

関連

本記事では送信方式の比較にフォーカスしましたが、tracing → OpenTelemetry → Datadog の各境界でスパンがどう変換されるかといった計装側の話題は、技術書典20の寄稿で扱っています。変換の内部構造やデバッグの切り口に興味がある方はあわせてご覧ください。


本記事の内容は以下のバージョンに基づいています

  • datadog-opentelemetry 0.2.1 / opentelemetry 0.31 / tracing-opentelemetry 0.32
脚注
  1. コンパイル時にこの置き換えを自動化する Orchestrion も提供されています。 ↩︎

  2. Datadog Agent 以外にも、OpenTelemetry Collector(Datadog Exporter)や Datadog OTLP Intake Endpoint といった経路もあります。 ↩︎

  3. Datadog APM は service(サービスの識別)、operation_name(操作の種類、低カーディナリティ)、resource(具体的なリソース、集計単位)、type(スパンの分類、Flame Graph の色分け)の 4 フィールドを軸に UI を構築しています。OTel は http.request.method = "GET" や http.route = "/api/users" のようにフラットな属性を持ちますが、Datadog はこれらを組み合わせて resource = "GET /api/users" のような値を期待します。 ↩︎

  4. 各クレートの Cargo.toml から cargo metadata で non-optional かつ normal な直接依存を取得し、opentelemetry で始まるクレートを除外してカウントしています。 ↩︎

estie テックブログ

Discussion