迁移到 OpenTelemetry Java - AWS X-Ray

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

迁移到 OpenTelemetry Java

本节提供有关从 X-Ray SDK 迁移到适用于 Java 应用程序的 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-Instrumention Java 代理使用 ADOT Java 代理进行自动检测。有关更多信息,请参阅使用 Java 代理自动检测跟踪和指标。如果您只想跟踪,请禁用OTEL_METRICS_EXPORTER=none 环境变量. 以从 Java 代理导出指标。

    (可选)您还可以在使用 ADOT Java 自动检测应用程序时启用 CloudWatch 应用程序信号,以监控当前应用程序的运行状况并跟踪长期应用程序性能。 AWS Application Signals 提供以应用程序为中心的统一视图,了解您的应用程序、服务和依赖关系,并帮助监控和分类应用程序的运行状况。有关更多信息,请参阅 Application Signals

  • 使用 OpenTelemetry Java 代理进行自动检测。有关更多信息,请参阅使用 Java 代理进行零代码检测

使用 SDK 的手动仪器解决方案

Tracing setup with X-Ray SDK

要使用适用于 Java 的 X-Ray SDK 来检测您的代码,首先需要为该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>

通过实例化来配置 OpenTelemetry SDK,TracerProvider然后全局注册一个对象。OpenTelemetrySdk配置以下组件:

  • OTLP Span 导出器(例如 OtlpGrpcSpanExporter)-将跟踪导出到 CloudWatch 代理或 OpenTelemetry 收集器时必需的

  • AWS X-Ray 传播器 — 将跟踪上下文传播到与 X-Ray 集成的 AWS 服务所必需的

  • AWS X-Ray-Remote 采样器 — 如果您需要使用 X-Ray 采样规则对请求进行采样,则需要使用

  • 资源检测器(例如, 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 框架工具)

With X-Ray SDK

有关如何使用带有 Spring 框架的 X-Ray SDK 来检测您的应用程序的信息,请参阅带有 Sprin g 的 AOP 和适用于 Java 的 X-Ray SDK。要在春季启用 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 相比,它还提供了更多的 out-of-the-box检测和配置。有关入门的信息,请参阅零代码自动检测解决方案

AWS 软件开发工具包 v2 插件

With X-Ray SDK

当你在版本中添加aws-xray-recorder-sdk-aws-sdk-v2-instrumentor子模块时,适用于 Java 的 X-Ray AWS SDK 可以自动检测所有 SDK v2 客户端。

要使用 AWS SDK for Java 2.2 及更高版本检测单个客户端对 AWS 服务的下游客户端调用,您的编译配置中已排除该aws-xray-recorder-sdk-aws-sdk-v2模块,并包含该模块。aws-xray-recorder-sdk-aws-sdk-v2-instrumentor 通过配置单个客户端来对其进行检测。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 请求,需要适用于 Java 的 Apache HttpClient 版本的 X-Ray SDK。

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 ApacheHttpClientTelemetry 类似,它 OpenTelemetry 提供了一个具有生成器方法的类,该方法允许创建 the 的实例,HttpClientBuilder以便为 A HttpClient pache 提供 OpenTelemetry基于跨度和上下文传播。

<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(); } }

对其他库的仪器支持

在 “支持的库、框架、应用程序服务器和” 下的相应工具 GitHub 库中查找支持 OpenTelemetry Java 的库工具的完整列表。 JVMs

或者,您可以搜索 OpenTelemetry 注册表以了解是否 OpenTelemetry 支持检测。要开始搜索,请参阅注册表

手动创建跟踪数据

With X-Ray SDK

使用 X-Ray SDK,需要使用beginSegmentbeginSubsegment方法来手动创建 X-Ray 分段和子分段。

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

您可以使用自定义跨度来监控未被仪器库捕获的内部活动的性能。请注意,只有跨度种类服务器会转换为 X-Ray 分段,所有其他跨度都会转换为 X-Ray 子分段。

首先,你需要创建一个 Tracer 来生成跨度,你可以通过该openTelemetry.getTracer方法获得跨度。这将提供示例中全局注册TracerProvider的 Tracer 实使用 SDK 的手动仪器解决方案例。您可以根据需要创建任意数量的 Tracer 实例,但通常为整个应用程序使用一个 Tracer。

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

你可以使用 Tracer 来创建跨度。

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();

跨度的默认类型为 “部”。

// 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方法用于向每个跨度添加属性。默认情况下,所有 span 属性都将转换为 X-Ray 原始数据中的元数据。为了确保将属性转换为注释而不是元数据,上面的示例将该属性的键添加到aws.xray.annotations属性列表中。有关更多信息,请参见启用自定义 X-Ray 注释注释以及元数据

使用 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 应用程序信号 Lambda 层(推荐)

    注意

    此 Lambda 层默认启用 CloudWatch 应用程序信号,通过收集指标和跟踪来监控您的 Lambda 应用程序的性能和运行状况。为了仅进行跟踪,请设置 Lambda 环境变量。 OTEL_AWS_APPLICATION_SIGNALS_ENABLED=false

    • 为您的 Lambda 应用程序启用性能和运行状况监控

    • 默认情况下会同时收集指标和跟踪

  • AWS 适用于 ADOT Java 的托管 Lambda 层。有关更多信息,请参阅适用于 Java 的 L AWS amb OpenTelemetry da Support 发行版

要将手动检测与自动检测层一起使用,请参见使用 SDK 的手动仪器解决方案。为了减少冷启动,可以考虑使用 OpenTelemetry 手动检测为您的 Lambda 函数生成 OpenTelemetry 跟踪。

OpenTelemetry 针对 AWS Lambda 的手动检测

考虑以下用于调用 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. 带有 X-Ray UDP 跨度导出器的简单跨度处理器,用于向 Lambda 的 UDP X-Ray 端点发送跟踪

    2. ParentBased 始终开启的采样器(如果未配置,则为默认值)

    3. 将 service.name 设置为 Lambda 函数名称的资源

    4. X-Ray Lambda 传播器

  3. handleRequest方法更改为doHandleRequest并将OpenTelemetrySdk对象传递给基类。

  4. 通过在构建客户端时注册拦截器,使用 OpenTemetry AWS 软件开发工具包检测 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 函数时,您将在控制台的 Trace Map 下看到以下跟踪。 CloudWatch

CloudWatch 控制台中的追踪地图。