ADOT Collector0.34からW3C形式のトレースIDをX-Ray形式に変換してエクスポートできるようになりました
CX事業部@大阪の岩田です。
先週のアップデートになるのですが、ADOT CollectorがW3C形式のトレースIDをX-Ray形式のトレースIDに変換してエクスポートしてくれるようになりました。
本ブログではこのアップデートについてご紹介します。
W3C形式とX-Ray形式のトレースIDの違い
X-Rayがリクエストを識別するために利用するトレースIDは、W3Cで定義されたフォーマットに準拠しておらず、X-Rayの独自形式となっています。両者は似たようなフォーマットではありますが、X-RayのトレースIDは以下の点でW3C形式と異なります。
- ハイフンで区切られた3つの要素で構成される
- W3C形式はトレースIDにハイフンを含まない
- 1要素目はバージョン番号を表す
1
が入る- 上記のハイフンと合わせてX-Ray形式のトレースIDは35桁となる
- W3C形式のトレースIDは32桁
- 2要素目は元のリクエストの時刻が16進数8桁で構成される
- W3C形式は先頭8桁が時刻を表すといったことはなく、ランダムな英数字で構成される
ざっくりした違いとしては先頭に1-
が付き、11桁目にも-
が入っていればX-Ray形式のトレースIDと考えておくと理解しやすいです。
これらの違いがあるため、従来はOTEL SDKでインストルメントしたトレースデータをX-Rayに送信したい場合は、AWS OpenTelemetry X-Ray IdGeneratorのようなライブラリを利用してX-Ray形式に準拠したトレースIDを生成する必要がありましたが、今回のアップデートによって、アプリケーション側でインストルメントする際にX-Ray形式のトレースIDを生成する必要が無くなりました。
やってみる
実際にADOT Collectorを利用してX-Rayにトレースデータをエクスポートできるかを試してみます。トレースデータを生成するために、NestJSで簡単なアプリを使ってインストルメントしていきます。
環境
今回は以下の環境で検証を行いました
- Node.js: v18.12
- Nest.JS: 9.0.0
- @opentelemetry/sdk-node: 0.44.0
- @opentelemetry/instrumentation-http: 0.44.0
- @opentelemetry/exporter-trace-otlp-http: 0.43.0
ADOT Collector0.33で試してみる
まず今回のアップデート以前の最新バージョンであるADOT Collector0.33を使ってX-Rayにトレースデータが送信できないことを確認しておきます。まずはNest CLIでアプリの雛形を作成します。
npx @nestjs/cli new blog
続いてOTEL関連のパッケージをインストールします。
yarn add @opentelemetry/instrumentation-http@0.44.0 @opentelemetry/sdk-node@0.44.0 @opentelemetry/exporter-trace-otlp-http@0.43.0
main.tsを以下のように修正し、ADOT Collectorにトレースデータを送信するようにします。
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { NodeSDK } from '@opentelemetry/sdk-node'; import { Resource } from '@opentelemetry/resources'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { HttpInstrumentation } from '@opentelemetry/instrumentation-http' import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; const exporterOptions = { url: process.env.OTLP_TRACE_ENDPOINT ?? 'http://127.0.0.1:4318/v1/traces', }; const traceExporter = new OTLPTraceExporter(exporterOptions); const otelSDK = new NodeSDK({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'blog', }), traceExporter, instrumentations: [new HttpInstrumentation()], spanProcessor: new BatchSpanProcessor(traceExporter), }); async function bootstrap() { await otelSDK.start(); const app = await NestFactory.create(AppModule); await app.listen(3000); } bootstrap();
docker-composeを使ってADOT Collectorを起動します。docker-compose.yamlは以下の通りです。AWSのクレデンシャル情報はdocker-composeを実行するシェルの環境変数経由で渡す構成としています。
version: '3.8' services: otel-collector: image: public.ecr.aws/aws-observability/aws-otel-collector:v0.33.0 ports: - '4318:4318' environment: AWS_REGION: ap-northeast-1 AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN} AOT_CONFIG_CONTENT: | receivers: otlp: protocols: http: endpoint: 0.0.0.0:4318 processors: batch/traces: timeout: 1s send_batch_size: 50 exporters: awsxray: logging: verbosity: detailed sampling_initial: 5 sampling_thereafter: 200 service: pipelines: traces: receivers: [otlp] processors: [batch/traces] exporters: [logging,awsxray]
AWS_ACCESS_KEY_ID="...略" AWS_SECRET_ACCESS_KEY="...略" AWS_SESSION_TOKEN="...略" docker-compose up
OTEL Collectorの準備ができたので、yarn start
等でNestJSのアプリを起動して適当にアクセスしてみましょう。しばらく待つと、docker-composeを実行しているシェルの標準出力にトレースデータが出力されます。出力されたトレースIDを見ると分かりますが、トレースIDの形式はW3C形式となっています。
blog-otel-collector-1 | ScopeSpans #0 blog-otel-collector-1 | ScopeSpans SchemaURL: blog-otel-collector-1 | InstrumentationScope @opentelemetry/instrumentation-http 0.44.0 blog-otel-collector-1 | Span #0 blog-otel-collector-1 | Trace ID : f8ab80d81cb069685f65017600a24486 blog-otel-collector-1 | Parent ID : blog-otel-collector-1 | ID : c4b64e16503f32b1 blog-otel-collector-1 | Name : GET blog-otel-collector-1 | Kind : Server blog-otel-collector-1 | Start time : 2023-11-05 12:08:30.207 +0000 UTC blog-otel-collector-1 | End time : 2023-11-05 12:08:30.2207334 +0000 UTC blog-otel-collector-1 | Status code : Unset blog-otel-collector-1 | Status message : blog-otel-collector-1 | Attributes: ...略
CloudWatchのマネコンからトレースデータを確認しにいきますが、トレースデータは確認できません。
トレースIDの形式不一致のため、うまくX-Rayと連携できていないようですね。
ADOT Collector0.34で試してみる
今度は現時点で最新版のADOT Collector0.34を利用する構成で再チャレンジしてみます。docker-compose.yamlの内容を修正し、ADOT Collectorのバージョンを0.34に更新します。
4c4 < image: public.ecr.aws/aws-observability/aws-otel-collector:v0.34.0 --- > image: public.ecr.aws/aws-observability/aws-otel-collector:v0.33.0
先程と同様にADOT Collectorを起動して再度NestJSのアプリケーションにアクセスします。標準出力に出力されたトレースIDは先程同様W3C形式です。
blog-otel-collector-1 | ScopeSpans #0 blog-otel-collector-1 | ScopeSpans SchemaURL: blog-otel-collector-1 | InstrumentationScope @opentelemetry/instrumentation-http 0.44.0 blog-otel-collector-1 | Span #0 blog-otel-collector-1 | Trace ID : f3cf41638bcdd2e254dff259fac8d84b blog-otel-collector-1 | Parent ID : blog-otel-collector-1 | ID : 4b704193097413ed blog-otel-collector-1 | Name : GET blog-otel-collector-1 | Kind : Server blog-otel-collector-1 | Start time : 2023-11-05 12:15:03.568 +0000 UTC blog-otel-collector-1 | End time : 2023-11-05 12:15:03.5702106 +0000 UTC blog-otel-collector-1 | Status code : Unset blog-otel-collector-1 | Status message : blog-otel-collector-1 | Attributes: ...略
続いてCloudWatchのマネコンを確認すると...
今度はバッチリトレースデータが確認できます。送信された生データを確認すると、トレースIDがX-Ray形式のトレースIDになっていることが分かります。
ちなみに、CloudWatchではなくX-Rayのマネコンでトレースデータを確認すると「経過時間」がおかしなことになっています。
W3C形式のトレースIDでは先頭8桁 = タイムスタンプというわけではないのですが、X-RayのマネコンがトレースIDの先頭8桁をタイムスタンプをして解釈していることが原因と思われます。この表示については今後修正される可能性もありそうですが、基本的にはトレースデータの確認はCloudWatchのマネコンを利用するように移行していくのが良いでしょう。
まとめ
ADOT Collector 0.34以後を利用することで、アプリ側でAWS OpenTelemetry X-Ray IdGeneratorを利用しなくてもX-Rayにトレースデータが送信できるようになりました。W3C形式のトレースIDを利用することで、他のSaaS製品等との相互運用性が高まるので、今後アプリケーションのトレースを実装する際には選択肢の1つとして頭に入れておきたいですね。