本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
迁移到 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,需要使用beginSegment
和beginSubsegment
方法来手动创建 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 层:
要将手动检测与自动检测层一起使用,请参见使用 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 客户端,请执行以下操作。
将实现RequestHandler
(或 RequestStreamHandler)的函数类替换为扩展TracingRequestHandler
(或 TracingRequestStreamHandler)的函数类。
实例化一个对象 TracerProvider 并全局注册一个对象。 OpenTelemetrySdk 建议配置为: TracerProvider
带有 X-Ray UDP 跨度导出器的简单跨度处理器,用于向 Lambda 的 UDP X-Ray 端点发送跟踪
ParentBased 始终开启的采样器(如果未配置,则为默认值)
将 service.name 设置为 Lambda 函数名称的资源
X-Ray Lambda 传播器
将handleRequest
方法更改为doHandleRequest
并将OpenTelemetrySdk
对象传递给基类。
通过在构建客户端时注册拦截器,使用 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