OpenTelemetry Java への移行 - AWS X-Ray

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

OpenTelemetry Java への移行

このセクションでは、Java アプリケーションの X-Ray SDK から OpenTelemetry SDK への移行に関するガイダンスを提供します。

ゼロコード自動計装ソリューション

With X-Ray Java agent

X-Ray Java エージェントを有効にする場合、アプリケーションの JVM 引数を変更する必要がありました。

-javaagent:/path-to-disco/disco-java-agent.jar=pluginPath=/path-to-disco/disco-plugins
With OpenTelemetry-based Java agent

OpenTelemetry ベースの Java エージェントを使用する方法

  • AWS Distro for OpenTelemetry (ADOT) Auto-Instrumentation Java エージェントを使用して、ADOT Java エージェントによる自動計測を行います。詳細については、「Auto-Instrumentation for Traces and Metrics with the Java agent」を参照してください。トレースのみが必要な場合は、OTEL_METRICS_EXPORTER=none 環境変数を無効にし、Java エージェントからメトリクスをエクスポートします。

    (オプション) ADOT Java 自動計測 AWS を使用して でアプリケーションを自動的に計測するときに CloudWatch Application Signals を有効にして、現在のアプリケーションの状態をモニタリングし、長期的なアプリケーションパフォーマンスを追跡することもできます。Application Signals は、アプリケーション、サービス、依存関係をアプリケーション中心の統合ビューで表示し、アプリケーションの状態をモニタリングしてトリアージできるようにします。詳細については、「Application Signals」を参照してください。

  • 自動計装に OpenTelemetry Java エージェントを使用します。詳細については、「Java エージェントでのゼロコード計装」を参照してください。

SDK を使用した手動計装ソリューション

Tracing setup with X-Ray SDK

X-Ray SDK for Java を使用してコードを計装するには、まず AWSXRay クラスをサービスプラグインとローカルサンプリングルールで設定する必要があり、次に提供されたレコーダーを使用しました。

static { AWS XRayRecorderBuilder builder = AWS XRayRecorderBuilder.standard().withPlugin(new EC2Plugin()).withPlugin(new ECSPlugin()); AWS XRay.setGlobalRecorder(builder.build()); }
Tracing setup with OpenTelemetry SDK

以下の依存関係は必須です。

<dependencyManagement> <dependencies> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-bom</artifactId> <version>1.49.0</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>io.opentelemetry.instrumentation</groupId> <artifactId>opentelemetry-instrumentation-bom</artifactId> <version>2.15.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-api</artifactId> </dependency> <dependency> <groupId>io.opentelemetry.semconv</groupId> <artifactId>opentelemetry-semconv</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-exporter-otlp</artifactId> </dependency> <dependency> <groupId>io.opentelemetry.contrib</groupId> <artifactId>opentelemetry-aws-xray</artifactId> <version>1.46.0</version> </dependency> <dependency> <groupId>io.opentelemetry.contrib</groupId> <artifactId>opentelemetry-aws-xray-propagator</artifactId> <version>1.46.0-alpha</version> </dependency> <dependency> <groupId>io.opentelemetry.contrib</groupId> <artifactId>opentelemetry-aws-resources</artifactId> <version>1.46.0-alpha</version> </dependency> </dependencies>

TracerProvider をインスタンス化して OpenTelemetry SDK を設定し、OpenTelemetrySdk オブジェクトをグローバルに登録します。以下のコンポーネントを設定します。

  • OTLP スパンエクスポーター (OtlpGrpcSpanExporter など) – CloudWatch エージェントまたは OpenTelemetry コレクターにトレースをエクスポートするために必要です。

  • AWS X-Ray プロパゲーター – X-Ray と統合された AWS サービスにトレースコンテキストを伝達するために必要です

  • AWS X-Ray リモートサンプラー – X-Ray サンプリングルールを使用してリクエストをサンプリングする必要がある場合に必要です

  • Resource Detectors (EcsResource や Ec2Resource など) — アプリケーションを実行しているホストのメタデータを検出します。

    import io.opentelemetry.api.common.Attributes; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.contrib.aws.resource.Ec2Resource; import io.opentelemetry.contrib.aws.resource.EcsResource; import io.opentelemetry.contrib.awsxray.AwsXrayRemoteSampler; import io.opentelemetry.contrib.awsxray.propagator.AwsXrayPropagator; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.opentelemetry.sdk.trace.samplers.Sampler; import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME; // ... private static final Resource otelResource = Resource.create(Attributes.of(SERVICE_NAME, "YOUR_SERVICE_NAME")) .merge(EcsResource.get()) .merge(Ec2Resource.get()); private static final SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(BatchSpanProcessor.create( OtlpGrpcSpanExporter.getDefault() )) .addResource(otelResource) .setSampler(Sampler.parentBased( AwsXrayRemoteSampler.newBuilder(otelResource).build() )) .build(); // Globally registering a TracerProvider makes it available throughout the application to create as many Tracers as needed. private static final OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(AwsXrayPropagator.getInstance())) .buildAndRegisterGlobal();

受信リクエストのトレース (Spring Framework の計装)

With X-Ray SDK

Spring Framework で X-Ray SDK を使用してアプリケーションを計装する方法については、「AOP with Spring and the X-Ray SDK for Java」を参照してください。Spring で AOP を有効にするには、以下の手順を実行します。

With OpenTelemetry SDK

OpenTelemetry は、Spring Boot アプリケーションの受信リクエストのトレースを収集するための計装ライブラリを提供します。最小限の設定で Spring Boot 計装を有効にするには、次の依存関係を含めます。

<dependency> <groupId>io.opentelemetry.instrumentation</groupId> <artifactId>opentelemetry-spring-boot-starter</artifactId> </dependency>

OpenTelemetry のセットアップで Spring Boot 計装を有効にして設定する方法の詳細については、OpenTelemetry の「はじめに」を参照してください。

Using OpenTelemetry-based Java agents

Spring Boot アプリケーションを計装するためのデフォルトの推奨方法は、OpenTelemetry Java エージェントバイトコード計装を使用することです。これにより、SDK を直接使用する場合と比較してすぐに使える計装と設定が多くなります。開始するには、「ゼロコード自動計装ソリューション」を参照してください。

AWS SDK v2 計測

With X-Ray SDK

X-Ray SDK for Java は、ビルドにaws-xray-recorder-sdk-aws-sdk-v2-instrumentorサブモジュールを追加したときに、すべての AWS SDK v2 クライアントを自動的に計測できます。

AWS SDK for Java 2.2 以降 AWS で個々のクライアントのダウンストリームクライアント呼び出しを計測するために、ビルド設定の aws-xray-recorder-sdk-aws-sdk-v2-instrumentor モジュールが除外され、 aws-xray-recorder-sdk-aws-sdk-v2モジュールが含まれていました。個々のクライアントは、TracingInterceptor で設定することで計装されました。

import com.amazonaws.xray.interceptors.TracingInterceptor; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration import software.amazon.awssdk.services.dynamodb.DynamoDbClient; //... public class MyModel { private DynamoDbClient client = DynamoDbClient.builder() .region(Region.US_WEST_2) .overrideConfiguration( ClientOverrideConfiguration.builder() .addExecutionInterceptor(new TracingInterceptor()) .build() ) .build(); //...
With OpenTelemetry SDK

すべての AWS SDK クライアントを自動的に計測するには、 opentelemetry-aws-sdk-2.2-autoconfigureサブモジュールを追加します。

<dependency> <groupId>io.opentelemetry.instrumentation</groupId> <artifactId>opentelemetry-aws-sdk-2.2-autoconfigure</artifactId> <version>2.15.0-alpha</version> <scope>runtime</scope> </dependency>

個々の AWS SDK クライアントを計測するには、 opentelemetry-aws-sdk-2.2サブモジュールを追加します。

<dependency> <groupId>io.opentelemetry.instrumentation</groupId> <artifactId>opentelemetry-aws-sdk-2.2</artifactId> <version>2.15.0-alpha</version> <scope>compile</scope> </dependency>

次に、 AWS SDK クライアントの作成時にインターセプターを登録します。

import io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkTelemetry; // ... AwsSdkTelemetry telemetry = AwsSdkTelemetry.create(openTelemetry); private final S3Client S3_CLIENT = S3Client.builder() .overrideConfiguration(ClientOverrideConfiguration.builder() .addExecutionInterceptor(telemetry.newExecutionInterceptor()) .build()) .build();

送信 HTTP 呼び出しの計測

With X-Ray SDK

X-Ray を使用して送信 HTTP リクエストを計装するには、X-Ray SDK for Java のバージョンの Apache HttpClient が必要でした。

import com.amazonaws.xray.proxies.apache.http.HttpClientBuilder; ... public String randomName() throws IOException { CloseableHttpClient httpclient = HttpClientBuilder.create().build();
With OpenTelemetry SDK

X-Ray Java SDK と同様に、OpenTelemetry は、Apache HttpClient に OpenTelemetry ベースのスパンとコンテキスト伝播を提供する HttpClientBuilder のインスタンスの作成を許可するビルダーメソッドを持つ ApacheHttpClientTelemetry クラスを提供します。

<dependency> <groupId>io.opentelemetry.instrumentation</groupId> <artifactId>opentelemetry-apache-httpclient-5.2</artifactId> <version>2.15.0-alpha</version> <scope>compile</scope> </dependency>

以下は、opentelemetry-java-instrumentation のコード例です。newHttpClient() によって提供される HTTP クライアントは、実行されたリクエストのトレースを生成します。

import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.apachehttpclient.v5_2.ApacheHttpClientTelemetry; import org.apache.hc.client5.http.classic.HttpClient; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; public class ApacheHttpClientConfiguration { private OpenTelemetry openTelemetry; public ApacheHttpClientConfiguration(OpenTelemetry openTelemetry) { this.openTelemetry = openTelemetry; } // creates a new http client builder for constructing http clients with open telemetry instrumentation public HttpClientBuilder createBuilder() { return ApacheHttpClientTelemetry.builder(openTelemetry).build().newHttpClientBuilder(); } // creates a new http client with open telemetry instrumentation public HttpClient newHttpClient() { return ApacheHttpClientTelemetry.builder(openTelemetry).build().newHttpClient(); } }

他のライブラリの計装サポート

OpenTelemetry Java でサポートされているライブラリ計装の全リストは、「Supported libraries, frameworks, application servers, and JVMs」の下にある、それぞれの計装 GitHub リポジトリにあります。

または、OpenTelemetry レジストリを検索して、OpenTelemetry が計装をサポートしているかどうかを調べることもできます。検索を開始するには、「Registry」を参照してください。

トレースデータを手動で作成する

With X-Ray SDK

X-Ray SDK では、X-Ray セグメントとサブセグメントを手動で作成するには、beginSegment および beginSubsegment メソッドが必要です。

Segment segment = xrayRecorder.beginSegment("ManualSegment"); segment.putAnnotation("annotationKey", "annotationValue"); segment.putMetadata("metadataKey", "metadataValue"); try { Subsegment subsegment = xrayRecorder.beginSubsegment("ManualSubsegment"); subsegment.putAnnotation("key", "value"); // Do something here } catch (Exception e) { subsegment.addException(e); } finally { xrayRecorder.endSegment(); }
With OpenTelemetry SDK

カスタムスパンを使用すると、計装ライブラリでキャプチャされない内部アクティビティのパフォーマンスをモニタリングできます。Server タイプのスパンのみが X-Ray セグメントに変換され、他のすべてのスパンは X-Ray サブセグメントに変換されることに注意してください。

まず、openTelemetry.getTracer メソッドで取得できるスパンを生成するには、トレーサーを作成する必要があります。これにより、「SDK を使用した手動計装ソリューション」の例でグローバルに登録した TracerProvider から 1 つのトレーサーインスタンスが提供されます。必要に応じていくつでもトレーサーインスタンスを作成できますが、アプリケーション全体で 1 つのトレーサーを持つことが一般的です。

Tracer tracer = openTelemetry.getTracer("my-app");

トレーサーを使用してスパンを作成できます。

import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; ... // SERVER span will become an X-Ray segment Span span = tracer.spanBuilder("get-token") .setKind(SpanKind.SERVER) .setAttribute("key", "value") .startSpan(); try (Scope ignored = span.makeCurrent()) { span.setAttribute("metadataKey", "metadataValue"); span.setAttribute("annotationKey", "annotationValue"); // The following ensures that "annotationKey: annotationValue" is an annotation in X-Ray raw data. span.setAttribute(AttributeKey.stringArrayKey("aws.xray.annotations"), List.of("annotationKey")); // Do something here } span.end();

スパンのデフォルトタイプは INTERNAL です。

// Default span of type INTERNAL will become an X-Ray subsegment Span span = tracer.spanBuilder("process-header") .startSpan(); try (Scope ignored = span.makeCurrent()) { doProcessHeader(); }

OpenTelemetry SDK を使用してトレースに注釈とメタデータを追加する

上記の例では、setAttribute メソッドを使用して各スパンに属性を追加します。デフォルトでは、すべてのスパン属性は X-Ray の未加工データのメタデータに変換されます。属性がメタデータではなく注釈に変換されるように、上記の例では、その属性のキーを aws.xray.annotations 属性のリストに追加しています。詳細については、「Enable the Customized X-Ray Annotations」および「注釈とメタデータ」を参照してください。

OpenTelemetry ベースの Java エージェントを使用する

Java エージェントを使用してアプリケーションを自動的に計装する場合は、アプリケーションで手動計装を実行する必要があります。例えば、自動計装ライブラリでカバーされていないセクションのコードをアプリケーション内で計装する場合です。

エージェントで手動計装を実行するには、opentelemetry-api アーティファクトを使用する必要があります。アーティファクトバージョンをエージェントバージョンより新しいものにすることはできません。

import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.Span; // ... Span parentSpan = Span.current(); Tracer tracer = GlobalOpenTelemetry.getTracer("my-app"); Span span = tracer.spanBuilder("my-span-name") .setParent(io.opentelemetry.context.Context.current().with(parentSpan)) .startSpan(); span.end();

Lambda 計装

With X-Ray SDK

X-Ray SDK を使用する場合、Lambda でアクティブトレースを有効にした後、X-Ray SDK を使用するための追加の設定は必要ありません。Lambda は Lambda ハンドラー呼び出しを表すセグメントを作成し、追加の設定なしで X-Ray SDK を使用してサブセグメントまたは計装ライブラリを作成できます。

With OpenTelemetry-based solutions

自動計測 Lambda レイヤー – 次のソリューションを使用して AWS 、販売された Lambda レイヤーを使用して Lambda を自動的に計測できます。

  • CloudWatch Application Signals Lambda レイヤー (推奨)

    注記

    この Lambda レイヤーでは、デフォルトで CloudWatch Application Signals が有効になっているため、メトリクスとトレースの両方を収集することで、Lambda アプリケーションのパフォーマンスとヘルスのモニタリングが可能になります。トレースのみの場合は、Lambda 環境変数 OTEL_AWS_APPLICATION_SIGNALS_ENABLED=false を設定します。

    • Lambda アプリケーションのパフォーマンスとヘルスのモニタリングが可能になります。

    • デフォルトでは、メトリクスとトレースの両方を収集します。

  • AWS ADOT Java 用の マネージド Lambda レイヤー。詳細については、「AWS Distro for OpenTelemetry Lambda Support For Java」を参照してください。

自動計装レイヤーとともに手動計装を使用するには、「SDK を使用した手動計装ソリューション」を参照してください。コールドスタートを減らすには、OpenTelemetry 手動計装を使用して Lambda 関数の OpenTelemetry トレースを生成することを検討してください。

AWS Lambda の OpenTelemetry 手動計測

Amazon S3 ListBuckets 呼び出しを行う次の Lambda 関数コードを検討してください。

package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.ListBucketsRequest; import software.amazon.awssdk.services.s3.model.ListBucketsResponse; import software.amazon.awssdk.services.s3.model.S3Exception; public class ListBucketsLambda implements RequestHandler<String, String> { private final S3Client S3_CLIENT = S3Client.builder() .build(); @Override public String handleRequest(String input, Context context) { try { ListBucketsResponse response = makeListBucketsCall(); context.getLogger().log("response: " + response.toString()); return "Success"; } catch (Exception e) { throw new RuntimeException(e); } } private ListBucketsResponse makeListBucketsCall() { try { ListBucketsRequest listBucketsRequest = ListBucketsRequest.builder() .build(); ListBucketsResponse response = S3_CLIENT.listBuckets(listBucketsRequest); return response; } catch (S3Exception e) { throw new RuntimeException("Failed to call S3 listBuckets" + e.awsErrorDetails().errorMessage(), e); } } }

依存関係は次のとおりです。

dependencies { implementation('com.amazonaws:aws-lambda-java-core:1.2.3') implementation('software.amazon.awssdk:s3:2.28.29') implementation('org.slf4j:slf4j-nop:2.0.16') }

Lambda ハンドラーと Amazon S3 クライアントを手動で計装するには、次の手順を実行します。

  1. RequestHandler (または RequestStreamHandler) を実装する関数クラスを、拡張する関数クラス TracingRequestHandler (または TracingRequestStreamHandler) に置き換えます。

  2. TracerProvider をインスタンス化し、OpenTelemetrySdk オブジェクトをグローバルに登録します。TracerProvider は、以下を使用して設定することをお勧めします。

    1. Lambda の UDP X-Ray エンドポイントにトレースを送信するための X-Ray UDP スパンエクスポーターを備えたシンプルなスパンプロセッサ

    2. ParentBased always on サンプラー (設定されていない場合はデフォルト)

    3. service.name が Lambda 関数名に設定されているリソース

    4. X-Ray Lambda プロパゲーター

  3. handleRequest メソッドを doHandleRequest に変更し、OpenTelemetrySdk オブジェクトをベースクラスに渡します。

  4. クライアントの構築時にインターセプターを登録して、OpenTemetry AWS SDK 計測を使用して Amazon S3 クライアントを計測します。

次の OpenTelemetry 関連の依存関係が必要です。

dependencies { ... implementation("software.amazon.distro.opentelemetry:aws-distro-opentelemetry-xray-udp-span-exporter:0.1.0") implementation(platform('io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.14.0')) implementation(platform('io.opentelemetry:opentelemetry-bom:1.48.0')) implementation('io.opentelemetry:opentelemetry-sdk') implementation('io.opentelemetry:opentelemetry-api') implementation('io.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.45.0-alpha') implementation('io.opentelemetry.contrib:opentelemetry-aws-resources:1.45.0-alpha') implementation('io.opentelemetry.instrumentation:opentelemetry-aws-lambda-core-1.0:2.14.0-alpha') implementation('io.opentelemetry.instrumentation:opentelemetry-aws-sdk-2.2:2.14.0-alpha') }

次のコードは、必要な変更が行われた後の Lambda 関数を示しています。追加のカスタムスパンを作成すると、自動的に提供されるスパンを補完できます。

package example; import java.time.Duration; import com.amazonaws.services.lambda.runtime.Context; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.contrib.aws.resource.LambdaResource; import io.opentelemetry.contrib.awsxray.propagator.AwsXrayLambdaPropagator; import io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestHandler; import io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkTelemetry; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.sdk.trace.samplers.Sampler; import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.ListBucketsRequest; import software.amazon.awssdk.services.s3.model.ListBucketsResponse; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.distro.opentelemetry.exporter.xray.udp.trace.AwsXrayUdpSpanExporterBuilder; public class ListBucketsLambda extends TracingRequestHandler<String, String> { private static final Resource lambdaResource = LambdaResource.get(); private static final SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create( new AwsXrayUdpSpanExporterBuilder().build() )) .addResource( lambdaResource .merge(Resource.create(Attributes.of(SERVICE_NAME, System.getenv("AWS_LAMBDA_FUNCTION_NAME")))) ) .setSampler(Sampler.parentBased(Sampler.alwaysOn())) .build(); private static final OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(AwsXrayLambdaPropagator.getInstance())) .buildAndRegisterGlobal(); private static final AwsSdkTelemetry telemetry = AwsSdkTelemetry.create(openTelemetry); private final S3Client S3_CLIENT = S3Client.builder() .overrideConfiguration(ClientOverrideConfiguration.builder() .addExecutionInterceptor(telemetry.newExecutionInterceptor()) .build()) .build(); public ListBucketsLambda() { super(openTelemetry, Duration.ofMillis(0)); } @Override public String doHandleRequest(String input, Context context) { try { ListBucketsResponse response = makeListBucketsCall(); context.getLogger().log("response: " + response.toString()); return "Success"; } catch (Exception e) { throw new RuntimeException(e); } } private ListBucketsResponse makeListBucketsCall() { try { ListBucketsRequest listBucketsRequest = ListBucketsRequest.builder() .build(); ListBucketsResponse response = S3_CLIENT.listBuckets(listBucketsRequest); return response; } catch (S3Exception e) { throw new RuntimeException("Failed to call S3 listBuckets" + e.awsErrorDetails().errorMessage(), e); } } }

Lambda 関数を呼び出すと、CloudWatch コンソールのトレースマップの下に次のトレースが表示されます。

CloudWatch コンソールのトレースマップ。