#23_OpenTelemetryとDataDogのトレース連携
サーバエンジニアの駒崎です。
WFS サーバチームでは OpenTelemetry の活用が広まりつつあり、特にアプリケーションパフォーマンスモニタリング (APM) を目的としての導入が進んでいます。今回はその一例として、DataDog との連携について書かせていただきます。
本エントリでは以下を扱います。
DataDog トレーシングライブラリと OpenTelemetry のトレースデータ関連付け
OpenTelemetry トレースデータを DataDog APM 上で扱うためのメタデータ設定
OpenTelemetry テレメトリデータの種類は一般にメトリクス、ログ、トレースと言われますが、ここではトレースについてのみ言及します。また、単一サービス内での事例をとりあげ、いわゆる分散トレースについては扱いません。
背景
OpenTelemetry はベンダー非依存なオブザーバビリティのためのプロジェクトです。テレメトリデータを収集するための API や SDK を提供しています。私たちのサーバアプリケーションの一部では、OpenTelemetry API/SDK (以下 OTel) を用いてトレースデータの出力を行っています。
テレメトリデータ計測の実装 (計装) に OTel を用いることで、アプリケーションは外部環境に依存しない計装を充実させることができます。ビジネス要件や規模など環境に応じてデータ収集・分析のツールやサービスを切り替えることが容易になり、ソースコードレベルの柔軟性を保つことができます。
OTel はベンダー非依存の仕様を定めていますが、データの可視化部分についてはスコープに含まれません。収集したデータは別途何らかのサービスを用いて可視化を行います。
私たちの一部のサービスでは本番環境の APM として DataDog を利用しています。このケースにおいて、DataDog の提供するトレーシングライブラリと OpenTelemetry トレースデータを連携して扱うための 設定例を紹介いたします。
本稿では PHP によるサーバアプリケーションを例としますが、基本的な用語と概念は他の言語やフレームワークでも同様かと思います。
OpenTelemetry & DataDog APM
OpenTelemetry トレースと DataDog APM の連携のためにポイントとなる 2 点についてまとめます。
トレースデータの関連付け
DataDog APM ではトレーシングライブラリ (以下 dd-trace ) を実行環境にインストールすることで、ソースコードへの変更なく自動的に多くのトレースを生成してくれます。
※これらの詳細については DataDog公式ドキュメントを参照ください
このコード片は PHP の Web フレームワーク Slim で Hello を返すコントローラ相当コードの一部です。特にロジック上の意味はありませんが途中で外部サイトへ HTTP リクエストを行っています。
// HelloAction.php
class HelloAction
{
public function __invoke($request, $response)
{
$this->myFunc();
$response->getBody()->write('Hello Observability World!');
return $response;
}
private function myFunc(): void
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.wfs.games/favicon.ico");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_exec($ch);
curl_close($ch);
}
}
dd-trace をインストール済みの環境でこれを動かすと、自動的に Slim フレームワークや cURL が検出されスパンが生成されます。トレースデータは DataDog エージェント (以下 dd-agent) で収集され次のようなトレースの可視化が得られます。
※スパンとは個々の動作を表現するブロックであり、一連の動作を表すトレースの構成要素となります。
ここに OTel を用いたスパン生成も追加してみます。( 通常利用では PHP 用 OpenTelemetry 拡張によるフックを用いるのが利便性が高いかと思いますが、ここでは明示的に追記します。)
use \OpenTelemetry\Context\Context
...
...
public function __invoke($request, $response)
{
$span = $this->tracer
->spanBuilder('HelloAction-mySpan')
->startSpan();
$c = Context::getCurrent();
Context::storage()->attach($span->storeInContext($c));
$this->myFunc();
$response->getBody()->write('Hello world!');
$span->setStatus(\OpenTelemetry\API\Trace\StatusCode::STATUS_OK);
$span->end();
return $response;
}
private function myFunc(): void
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.wfs.games/favicon.ico");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$span = $this->tracer
->spanBuilder('HelloAction-myFuncSpan')
->startSpan();
curl_exec($ch);
$span->end();
curl_close($ch);
}
追加された OTel のスパンはこのようになります。
dd-trace にしろ OTel を使うにしろパフォーマンス測定という目的は同じですので、これらのスパンを統一的に扱えると都合がよいかと思います。自前の OTel 実装に加え dd-trace を活かしたい場合、dd-trace に DD_TRACE_OTEL_ENABLED=true 環境変数を追加することで OTel 互換のトレーススパンを生成してくれるようになります。
また収集側である dd-agent は OpenTelemetry の通信プロトコル OTLP に対応しています。以下のように設定ファイル datadog.yaml で有効化することが必要ですが、OTel で生成したトレーススパンも dd-agent にまとめることができます。
# datadog.yaml
otlp_config:
receiver:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
このときアプリケーション側には OTel トレースエクスポーターから dd-agent へ送信させるため、OTEL_EXPORTER_OTLP_ENDPOINT="http://dd-agent-name:4318" のように宛先の環境変数を設定します。
ここまでの設定により上図の中央部下側 "DATADOG AGENT" を通る経路を実現していることになります。収集されたトレースは DataDog APM 上で以下のように統合されます。
少し実装面から踏み込むと、dd-trace が有効化された環境では OTel の SpanBuilderInterface::startSpan() などの実装が DataDog 実装に切り替わるようです。アプリケーションコード側からは OTel のインターフェースで扱うため特に意識することはないかと思いますが、これにより DataDog 向けにコンテキスト伝搬が行われているようです。
また dd-trace が自動で生成するスパンは SpanProcessor としては no-op 設定されていてエクスポータは含まないようですので、このスパンを OTLP で Otel Collector などに送ることはできません。(図の左下から中上への経路がないことに相当)
トレースデータへのメタデータ設定
収集された大量のデータを意味のある単位で可視化するためにはメタデータが不可欠です。OpenTelemetry ではセマンティック規約として付加情報の名前を定めています。ここではDataDog APM を利用する場合に行うべき設定という観点で一部を紹介いたします。
DataDog では env , service , version などが主要なタグ情報として扱われています。OpenTelemetry のトレースデータをこれらに対応させるには以下のようなマッピングに従います。
env : deployment.environment または deployment.environment.name
注: deployment.environment は deprecated
service : service.name
version : service.version
これらの値は環境変数から OpenTelemetry SDK へ渡すことができるので、通常はコード内に直接記述する必要はありません。デプロイ環境にあわせて注入させることが可能です。
前述したトレースの取得の際には、アプリケーションコンテナに次のような環境変数を指定し、DataDog APM での表示を行いました。
OTEL_SERVICE_NAME="myApp"
OTEL_RESOURCE_ATTRIBUTES="deployment.environment.name=myDevelopment,service.version=0.1.2-test"
この節の趣旨とは少しずれますが、テレメトリデータの付加情報はオブザーバビリティの観点からも重要です。意図的に計測を試みた対象から得られるデータが「既知の未知」の解明につながるとするならば、コンテキストやスパン属性など付加的に収集される情報の集合により結果として紡がれるデータは「未知の未知」を見つけ出すことに役立つと考えます。
自動計装の有効化、無効化
DataDog トレーシングライブラリは多くのライブラリやフレームワークを自動的に検出しトレースデータを生成する、と書きました。これと同等ではありませんが、OpenTelemetry の枠組みとしても自動計装のライブラリが開発されています。
PHP の例では opentelemetry-auto- プレフィクスのパッケージなどが相当しているようです。
こういったものを使う場合 DataDog トレーシングライブラリと目的が被ることも多いので、状況に応じ有効化または無効化したいケースもあるかと思います。
PHP パッケージの場合は、 OTEL_PHP_DISABLED_INSTRUMENTATIONS 環境変数でライブラリ別に無効化設定ができます。DataDog トレーシングライブラリについては、DD_TRACE_ENABLED 環境変数を false にすることで DataDog エージェントへのデータ送信が停止されます。
私たちのサービス開発の例では、ローカル開発環境では OTel 自動計装ライブラリ + OpenTelemetry Collector + Grafana + Grafana Tempo といった OSS 構成とし、本番環境では DataDog トレーシングの有効化 + DataDog エージェントで収集&送信、といった切り替え運用をしています。
おわりに
アプリケーションの計装に OpenTelemetry API/SDK を使いつつ、DataDog APM とトレーシングライブラリを活用するための設定例を紹介いたしました。本エントリで扱ったこれらの設定をまとめて環境変数で指定するとすると、例えば次のような値になるでしょう。
# DataDog トレーシングライブラリの設定
DD_TRACE_OTEL_ENABLED="true"
DD_TRACE_AGENT_URL="http://dd-agent:8126"
# OpenTelemetry 計装の設定
## PHP SDK ロード有効化
OTEL_PHP_AUTOLOAD_ENABLED="true"
## dd-agent へ OTLP でスパンを送信
OTEL_EXPORTER_OTLP_ENDPOINT="http://dd-agent:4318"
## リソース属性の設定
OTEL_SERVICE_NAME="myApp"
OTEL_RESOURCE_ATTRIBUTES="deployment.environment.name=myDevelopment,service.version=0.1.2-test"
## 特定の環境で無効にしたい自動計装を指定
OTEL_PHP_DISABLED_INSTRUMENTATIONS="slim,guzzle"
OpenTelemetry を活用するための構成パターンは多くあると思いますが、同じような構成を導入、検討している方の参考になれば幸いです。