ADOT Collector0.34からW3C形式のトレースIDをX-Ray形式に変換してエクスポートできるようになりました

2023.11.05

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のマネコンからトレースデータを確認しにいきますが、トレースデータは確認できません。

CloudWatchのマネコんからトレースデータを確認した結果1

トレース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のマネコンを確認すると...

CloudWatchのマネコんからトレースデータを確認した結果2

今度はバッチリトレースデータが確認できます。送信された生データを確認すると、トレースIDがX-Ray形式のトレースIDになっていることが分かります。

CloudWatchのマネコンから確認した生のトレースデータ

ちなみに、CloudWatchではなくX-Rayのマネコンでトレースデータを確認すると「経過時間」がおかしなことになっています。

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つとして頭に入れておきたいですね。

参考