Amazon X-Ray 适用于 Java - Amazon X-Ray
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

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

Amazon X-Ray 适用于 Java

适用于 Java 的 X-Ray SDK 是一组用于 Java Web 应用程序的库,它们提供用于生成跟踪数据并将其发送到 X-Ray 守护程序的类和方法。跟踪数据包括有关应用程序处理的传入 HTTP 请求的信息,以及应用程序使用 Amazon SDK、HTTP 客户端或 SQL 数据库连接器对下游服务进行的调用的信息。您还可以手动创建分段并在注释和元数据中添加调试信息。

适用于 Java 的 X-Ray 开发工具包是一个开源项目。你可以通过以下网址关注该项目并提交议题和拉取请求 GitHub:github.co m/aws/ aws-xray-sdk-java

首先通过添加AWSXRayServletFilter 作为 servlet 筛选器来跟踪传入请求。servlet 筛选器会创建分段。当分段打开时,您可以使用开发工具包客户端的方法将信息添加到分段,并创建子分段以跟踪下游调用。开发工具包还会自动记录在分段打开时应用程序引发的异常。

从版本 1.3 开始,您可以使用 Spring 中的面向方面的编程 (AOP) 来检测应用程序。这意味着您可以在应用程序运行时对其进行检测,而无需在 Amazon应用程序的运行时中添加任何代码。

接下来,使用适用于 Java 的 X-Ray SDK,在构建配置中包含 SDK Instrumentor 子模块,对 Amazon SDK for Java 客户进行检测。每当您使用已检测的客户端调用下游 Amazon Web Service 或资源时,SDK 都会在子分段中记录有关该调用的信息。 Amazon Web Services 您在服务中访问的资源将作为下游节点显示在跟踪地图上,以帮助您识别各个连接上的错误和限制问题。

如果您不想检测所有下游调用 Amazon Web Services,则可以省略 Instrumentor 子模块,然后选择要检测的客户端。通过向 Amazon SDK 服务客户端添加TracingHandler来检测各个客户端。

其他适用于 Java 的 X-Ray 开发工具包子模块为对 HTTP Web API 和 SQL 数据库的下游调用提供检测。您可以使用适用于 Java 的 X-Ray 开发工具包的 HTTPClient 版本和 Apache HTTP 子模块中的 HTTPClientBuilder 来检测 Apache HTTP 客户端。要检测 SQL 查询,请将开发工具包的拦截程序添加到数据源

在开始使用开发工具包后,通过配置记录器和 servlet 筛选器来自定义其行为。您可以添加插件来记录有关应用程序上运行的计算资源的数据,通过定义采样规则来自定义采样行为,设置日志级别以在应用程序日志中查看来自开发工具包的更多或更少的信息。

记录有关请求以及应用程序在注释和元数据中所做的工作的其他信息。注释是简单的键值对,已为这些键值对编制索引以用于筛选条件表达式,以便您能够搜索包含特定数据的跟踪。元数据条目的限制性较低,并且可以记录整个对象和数组 - 可序列化为 JSON 的任何项目。

注释和元数据

注释和元数据是您使用 X-Ray 开发工具包添加到分段的任意文本。系统会对注释编制索引,以便与筛选表达式一起使用。元数据未编制索引,但可以使用 X-Ray 控制台或 API 在原始分段中查看。您授予 X-Ray 读取权限的任何人都可以查看这些数据。

当代码中具有大量检测的客户端时,一个请求分段可包含许多子分段,检测的客户端发起的每个调用均对应一个子分段。您可以通过将客户端调用包含在自定义子分段中来整理子分段并为其分组。您可以为整个函数或任何代码部分创建自定义子分段,并记录子分段的元数据和注释,而不是编写父分段的所有内容。

子模块

你可以从 Maven 下载适用于 Java 的 X-Ray 开发工具包。适用于 Java 的 X-Ray 开发工具包按使用案例被拆分为子模块,其中的材料清单用于版本管理:

如果您使用 Maven 或 Gradle 来构建应用程序,则将适用 Java 的 X-Ray 开发工具包添加到您的生成配置中

有关 SDK 的类和方法的参考文档,请参阅 Amazon X-Ray SDK for Java API 参考

要求

适用于 Java 的 X-Ray SDK 需要 Java 8 或更高版本、Servlet API 3、 Amazon SDK 和 Jackson。

开发工具包在编译和运行时依赖于以下库:

  • Amazon 适用于 1.11.398 或更高Java版本的 SDK

  • Servlet API 3.1.0

这些依赖项在开发工具包的 pom.xml 文件中声明,如果您使用 Maven 或 Gradle 生成则自动包括在内。

如果您使用包括在适用 Java 的 X-Ray 开发工具包中的库,则必须使用包括的版本。例如,如果您在运行时已经依赖于 Jackson 并在部署中为该依赖项包括了 JAR 文件,则必须删除这些 JAR 文件,因为开发工具包 JAR 包括其自己的 Jackson 库版本。

依赖项管理

可从 Maven 获得适用于 Java 的 X-Ray 开发工具包:

  • com.amazonaws

  • 构件aws-xray-recorder-sdk-bom

  • 版本2.11.0

如果您使用 Maven 来生成应用程序,则在 pom.xml 文件中添加开发工具包作为依赖项。

例 pom.xml - 依赖项
<dependencyManagement> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-xray-recorder-sdk-bom</artifactId> <version>2.11.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-xray-recorder-sdk-core</artifactId> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-xray-recorder-sdk-apache-http</artifactId> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-xray-recorder-sdk-aws-sdk</artifactId> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-xray-recorder-sdk-aws-sdk-instrumentor</artifactId> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-xray-recorder-sdk-sql-postgres</artifactId> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-xray-recorder-sdk-sql-mysql</artifactId> </dependency> </dependencies>

对于 Gradle,添加开发工具包作为 build.gradle 文件中的编译时依赖项。

例 build.gradle - 依赖项
dependencies { compile("org.springframework.boot:spring-boot-starter-web") testCompile("org.springframework.boot:spring-boot-starter-test") compile("com.amazonaws:aws-java-sdk-dynamodb") compile("com.amazonaws:aws-xray-recorder-sdk-core") compile("com.amazonaws:aws-xray-recorder-sdk-aws-sdk") compile("com.amazonaws:aws-xray-recorder-sdk-aws-sdk-instrumentor") compile("com.amazonaws:aws-xray-recorder-sdk-apache-http") compile("com.amazonaws:aws-xray-recorder-sdk-sql-postgres") compile("com.amazonaws:aws-xray-recorder-sdk-sql-mysql") testCompile("junit:junit:4.11") } dependencyManagement { imports { mavenBom('com.amazonaws:aws-java-sdk-bom:1.11.39') mavenBom('com.amazonaws:aws-xray-recorder-sdk-bom:2.11.0') } }

如果您使用 Elastic Beanstalk 来部署应用程序,则可以使用 Maven 或 Gradle 在每次部署时生成 on-instance,而不是生成和上传包括所有依赖项的大档案。有关使用 Gradle 的示例,请参阅示例应用程序

配置适用于 Java 的 X-Ray 开发工具包

适用于 Java 的 X-Ray 开发工具包包括提供全局记录器的、名为 AWSXRay 的类。这是可用于检测代码的 TracingHandler。您可以配置全局记录器以自定义为传入 HTTP 调用创建分段的 AWSXRayServletFilter

服务插件

plugins 用于记录有关托管应用程序的服务的信息。

插件
  • Amazon EC2 — EC2Plugin 添加实例 ID、可用区和 CloudWatch 日志组。

  • Elastic Beanstalk - ElasticBeanstalkPlugin 添加环境名称、版本标签和部署 ID。

  • Amazon ECS — ECSPlugin 添加容器 ID。

  • Amazon EKS — EKSPlugin 添加容器 ID、集群名称、容器 ID 和 CloudWatch 日志组。


        使用 Amazon EC2 和 Elastic Beanstalk 插件对资源数据进行分段。

要使用插件,请在 AWSXRayRecorderBuilder 上调用 withPlugin

例 src/main/java/scorekeeep/ WebConfig .java-录音机
import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.AWSXRayRecorderBuilder; import com.amazonaws.xray.plugins.EC2Plugin; import com.amazonaws.xray.plugins.ElasticBeanstalkPlugin; import com.amazonaws.xray.strategy.sampling.LocalizedSamplingStrategy; @Configuration public class WebConfig { ... static { AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder.standard().withPlugin(new EC2Plugin()).withPlugin(new ElasticBeanstalkPlugin()); URL ruleFile = WebConfig.class.getResource("/sampling-rules.json"); builder.withSamplingStrategy(new LocalizedSamplingStrategy(ruleFile)); AWSXRay.setGlobalRecorder(builder.build()); } }

开发工具包还使用插件设置为设置分段上的 origin 字段。这表示运行应用程序的 Amazon 资源类型。当您使用多个插件时,软件开发工具包使用以下解析顺序来确定来源: ElasticBeanstalk > EKS > ECS > EC2。

采样规则

开发工具包使用您在 X-Ray 控制台中定义的采样规则来确定要记录的请求。默认规则跟踪每秒的第一个请求,以及所有将跟踪发送到 X-Ray 的服务的任何其他请求的百分之五。在 X-Ray 控制台中创建其他规则以自定义为每个应用程序记录的数据量。

开发工具包按照定义的顺序应用自定义规则。如果请求与多个自定义规则匹配,则开发工具包仅应用第一条规则。

注意

如果开发工具包无法访问 X-Ray 来获取采样规则,它将恢复为默认的本地规则,即每秒第一个请求以及每个主机所有其他请求的百分之五。如果主机无权调用采样 API 或者无法连接到 X-Ray 进程守护程序,后者充当开发工具包发出的 API 调用的 TCP 代理,则可能会发生这种情况。

您还可以将开发工具包配置为从 JSON 文档加载采样规则。在 X-Ray 采样不可用的情况下,开发工具包可以使用本地规则作为备份,也可以只使用本地规则。

例 sampling-rules.json
{ "version": 2, "rules": [ { "description": "Player moves.", "host": "*", "http_method": "*", "url_path": "/api/move/*", "fixed_target": 0, "rate": 0.05 } ], "default": { "fixed_target": 1, "rate": 0.1 } }

此示例定义了一个自定义规则和一个默认规则。自定义规则采用百分之五的采样率,对于 /api/move/ 之下的路径要跟踪的请求数量不设下限。默认规则中每秒的第一个请求以及其他请求的百分之十。

在本地定义规则的缺点是,固定目标由记录器的每个实例独立应用而不是由 X-Ray 服务管理。随着您部署更多主机,固定速率会成倍增加,这使得控制记录的数据量变得更加困难。

开启后 Amazon Lambda,您无法修改采样率。如果您的函数由检测服务调用,Lambda 将记录生成由该服务采样的请求的调用。如果启用了主动跟踪且不存在任何跟踪标头,则 Lambda 会做出采样决定。

要在 Spring 中提供备份规则,请使用配置类中的 CentralizedSamplingStrategy 配置全局记录器。

例 src/main/java/myapp/ .java WebConfig-录音机配置
import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.AWSXRayRecorderBuilder; import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter; import com.amazonaws.xray.plugins.EC2Plugin; import com.amazonaws.xray.strategy.sampling.LocalizedSamplingStrategy; @Configuration public class WebConfig { static { AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder.standard().withPlugin(new EC2Plugin()); URL ruleFile = WebConfig.class.getResource("/sampling-rules.json"); builder.withSamplingStrategy(new CentralizedSamplingStrategy(ruleFile)); AWSXRay.setGlobalRecorder(builder.build()); }

对于 Tomcat,添加一个扩展 ServletContextListener 的侦听器,并在部署描述符中注册该侦听器。

例 src/com/myapp/web/Startup.java
import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.AWSXRayRecorderBuilder; import com.amazonaws.xray.plugins.EC2Plugin; import com.amazonaws.xray.strategy.sampling.LocalizedSamplingStrategy; import java.net.URL; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class Startup implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent event) { AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder.standard().withPlugin(new EC2Plugin()); URL ruleFile = Startup.class.getResource("/sampling-rules.json"); builder.withSamplingStrategy(new CentralizedSamplingStrategy(ruleFile)); AWSXRay.setGlobalRecorder(builder.build()); } @Override public void contextDestroyed(ServletContextEvent event) { } }
例 WEB-INF/web.xml
... <listener> <listener-class>com.myapp.web.Startup</listener-class> </listener>

若要仅使用本地规则,请将 CentralizedSamplingStrategy 替换为 LocalizedSamplingStrategy

builder.withSamplingStrategy(new LocalizedSamplingStrategy(ruleFile));

日志记录

默认情况下,开发工具包会将 ERROR 级消息输出到应用程序日志。可以在开发工具包上启用调试级别日志记录,将更详细的日志输出到应用程序日志文件。有效的日志级别为 DEBUGINFOWARNERRORFATALFATAL 日志级别会静默所有日志消息,因为开发工具包不会在严重级别记录日志。

例 application.properties

使用 logging.level.com.amazonaws.xray 属性设置日志记录级别。

logging.level.com.amazonaws.xray = DEBUG

当您手动生成子分段时,使用调试日志来识别诸如未结束子分段之类的问题。

跟踪 ID 注入到日志

要将当前完全限定的跟踪 ID 公开到日志语句,您可以将此 ID 注入到映射的诊断上下文 (MDC)。在分段生命周期事件过程中使用 SegmentListener 接口从 X-Ray 记录器调用方法。当分段或子分段开始时,使用密钥 AWS-XRAY-TRACE-ID 将限定的跟踪 ID 注入到 MDC 中。当该分段结束后,从 MDC 中删除密钥。这会向正在使用的日志库公开跟踪 ID。当子分段结束时,其父级 ID 将注入到 MDC 中。

例 完全限定的跟踪 ID

完全限定的 ID 表示为 TraceID@EntityID

1-5df42873-011e96598b447dfca814c156@541b3365be3dafc3

此功能适用于使用适用于 Java 的 Amazon X-Ray SDK 进行检测的 Java 应用程序,并支持以下日志配置:

  • 带有 Logback 后端的 SLF4J 前端 API

  • 带有 Log4J2 后端的 SLF4J 前端 API

  • 带有 Log4J2 后端的 Log4J2 前端 API

请查看以下选项卡,了解每个前端和每个后端的需求。

SLF4J Frontend
  1. 将以下 Maven 依赖项添加到您的项目中。

    <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-xray-recorder-sdk-slf4j</artifactId> <version>2.11.0</version> </dependency>
  2. 构建 AWSXRayRecorder 时包含 withSegmentListener 方法。这会增加一个 SegmentListener 类,它会自动将新的跟踪 ID 注入到 SLF4J MDC 中。

    SegmentListener 采用可选字符串作为参数来配置日志语句前缀。可以通过以下方式配置前缀:

    • - 使用默认 AWS-XRAY-TRACE-ID 前缀。

    • 使用空字符串(例如 "")。

    • 自定义 - 使用在字符串中定义的自定义前缀。

    AWSXRayRecorderBuilder statement
    AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder .standard().withSegmentListener(new SLF4JSegmentListener("CUSTOM-PREFIX"));
Log4J2 front end
  1. 将以下 Maven 依赖项添加到您的项目中。

    <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-xray-recorder-sdk-log4j</artifactId> <version>2.11.0</version> </dependency>
  2. 构建 AWSXRayRecorder 时包含 withSegmentListener 方法。这将增加一个 SegmentListener 类,它会自动将新的完全限定的跟踪 ID 注入到 SLF4J MDC 中。

    SegmentListener 采用可选字符串作为参数来配置日志语句前缀。可以通过以下方式配置前缀:

    • - 使用默认 AWS-XRAY-TRACE-ID 前缀。

    • - 使用空字符串(例如 "")并删除前缀。

    • 自定义 - 使用在字符串中定义的自定义前缀。

    AWSXRayRecorderBuilder statement
    AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder .standard().withSegmentListener(new Log4JSegmentListener("CUSTOM-PREFIX"));
Logback backend

要将跟踪 ID 插入到日志事件中,您必须修改记录器的 PatternLayout,它设置每个日志记录语句的格式。

  1. 查找在哪里配置的 patternLayout。您可以通过编程方式或通过 XML 配置文件执行此操作。要了解更多信息,请参阅 Logback 配置

  2. patternLayout 中的任意位置插入 %X{},将跟踪 ID 插入到未来的日志记录语句中。%X{AWS-XRAY-TRACE-ID} 指示您正在检索的值包含由 MDC 提供的密钥。要 PatternLayouts 在 Logback 中了解更多信息,请参阅PatternLayout

Log4J2 backend
  1. 查找在哪里配置的 patternLayout。您可以通过编程方式执行此操作,也可以通过以 XML、JSON、YAML 或属性格式编写的配置文件来执行此操作。

    如需详细了解如何通过配置文件配置 Log4J2,请参阅配置

    如需详细了解如何以编程方式配置 Log4J2,请参阅编程式配置

  2. PatternLayout 中的任意位置插入 %X{},将跟踪 ID 插入到未来的日志记录语句中。%X{AWS-XRAY-TRACE-ID} 指示您正在检索的值包含由 MDC 提供的密钥。要了解有关 Log4J2 PatternLayouts 的更多信息,请参阅模式布局。

跟踪 ID 注入示例

以下显示了一个经过修改包含跟踪 ID 的 PatternLayout 字符串。跟踪 ID 在线程名称 (%t) 之后和日志级别 (%-5p) 之前输出。

PatternLayout(带 ID 注入)
%d{HH:mm:ss.SSS} [%t] %X{AWS-XRAY-TRACE-ID} %-5p %m%n

Amazon X-Ray 自动在日志语句中打印密钥和跟踪 ID,便于解析。下面显示了使用已修改的 PatternLayout 的日志语句。

例 带 ID 注入的日志语句
2019-09-10 18:58:30.844 [nio-5000-exec-4] AWS-XRAY-TRACE-ID: 1-5d77f256-19f12e4eaa02e3f76c78f46a@1ce7df03252d99e1 WARN 1 - Your logging message here

日志记录消息本身保存在模式 %m 中,并在调用记录器时设置。

分段侦听器

分段侦听器是一个用于拦截生命周期事件(例如,由 AWSXRayRecorder 生成的分段的开始和结束)的接口。分段侦听器事件函数的实现可能是在使用 onBeginSubsegment 创建所有子分段时向所有子分段添加相同的注释,使用 afterEndSegment 将每个分段发送到进程守护程序后记录一条消息,或者使用 beforeEndSubsegment 记录由 SQL 拦截程序发送的查询,以验证子分段是否代表 SQL 查询,如果是,则添加其他元数据。

要查看 SegmentListener 函数的完整列表,请访问适用于 Java 的 Amazon X-Ray 记录器开发工具包 API 的文档。

以下示例说明如何在使用 onBeginSubsegment 创建所有子分段时向所有子分段添加一致的注释,以及如何使用 afterEndSegment 在每个分段末尾打印日志消息。

例 MySegmentListener.java
import com.amazonaws.xray.entities.Segment; import com.amazonaws.xray.entities.Subsegment; import com.amazonaws.xray.listeners.SegmentListener; public class MySegmentListener implements SegmentListener { ..... @Override public void onBeginSubsegment(Subsegment subsegment) { subsegment.putAnnotation("annotationKey", "annotationValue"); } @Override public void afterEndSegment(Segment segment) { // Be mindful not to mutate the segment logger.info("Segment with ID " + segment.getId()); } }

然后,在构建 AWSXRayRecorder 时引用此自定义分段侦听器。

例 AWSXRayRecorderBuilder 声明
AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder .standard().withSegmentListener(new MySegmentListener());

环境变量

您可以使用环境变量来配置适用于 Java 的 X-Ray 开发工具包。开发工具包支持以下变量。

  • AWS_XRAY_TRACING_NAME - 设置开发工具包用于进行分段的服务名称。覆盖您根据 servlet 筛选器的分段命名策略设置的服务名称。

  • AWS_XRAY_DAEMON_ADDRESS - 设置 X-Ray 进程守护程序侦听器的主机和端口。默认情况下,开发工具包使用用于跟踪数据 (UDP) 和采样 (TCP) 的 127.0.0.1:2000。如果您已将进程守护程序配置为侦听不同端口或者进程守护程序在另一台主机上运行,则使用此变量。

    格式
    • 同一个端口address:port

    • 不同的端口tcp:address:port udp:address:port

  • AWS_XRAY_CONTEXT_MISSING - 设置为 RUNTIME_ERROR 在您的已检测代码尝试在分段未打开的情况下记录数据时引发异常。

    有效值
    • RUNTIME_ERROR— 引发运行时异常。

    • LOG_ERROR— 记录错误并继续(默认)。

    • IGNORE_ERROR— 忽略错误并继续。

    对于在未打开任何请求时运行的启动代码或者会生成新线程的代码,如果您尝试在其中使用检测过的客户端,则可能发生与缺失分段或子分段相关的错误。

环境变量覆盖在代码中设置的等效系统属性和值。

系统属性

您可以将系统属性用作环境变量的 JVM 特定替代项。开发工具包支持以下属性:

  • com.amazonaws.xray.strategy.tracingName - 等效于 AWS_XRAY_TRACING_NAME

  • com.amazonaws.xray.emitters.daemonAddress - 等效于 AWS_XRAY_DAEMON_ADDRESS

  • com.amazonaws.xray.strategy.contextMissingStrategy - 等效于 AWS_XRAY_CONTEXT_MISSING

如果同时设置系统属性和等效的环境变量,则使用环境变量值。每种方法都会覆盖在代码中设置的值。

使用适用于 Java 的 X-Ray 开发工具包跟踪传入请求

您可以使用 X-Ray SDK 来跟踪您的应用程序在亚马逊 EC2 或 Amazon ECS 的 EC2 实例上提供的 Amazon Elastic Beanstalk传入 HTTP 请求。

使用 Filter 检测传入 HTTP 请求。在您添加 X-Ray servlet 筛选器到应用程序时,适用于 Java 的 X-Ray 开发工具包为每个采样请求创建分段。此分段包括 HTTP 请求的计时、方法和处置。其他检测会在此分段上创建子分段。

注意

对于 Amazon Lambda 函数,Lambda 会为每个采样请求创建一个分段。请参阅Amazon Lambda 和 Amazon X-Ray了解更多信息。

每个分段都有一个名称,用于在服务映射中标识您的应用程序。可以静态命名分段,也可以将开发工具包配置为根据传入请求中的主机标头对其进行动态命名。动态命名允许根据请求中的域名对跟踪进行分组,并且在名称不匹配预期模式时(例如,如果主机标头是伪造的)应用默认名称。

转发的请求

如果负载均衡器或其他中间将请求转发到您的应用程序,X-Ray 会提取请求 X-Forwarded-For 标头中的客户端 IP 而非 IP 数据包中的源 IP。由于转发的请求记录的客户端 IP 可以伪造,因此不应信任。

在转发请求时,开发工具包在分段中设置附加字段来指示此行为。如果分段包含设置为 x_forwarded_for 的字段 true,则从 HTTP 请求的 X-Forwarded-For 标头获取客户端 IP。

信息处理程序使用包含以下信息的 http 数据块为每个传入请求创建一个分段:

  • HTTP 方法 - GET、POST、PUT、DELETE 等。

  • 客户端地址 - 发送请求的客户端的 IP 地址。

  • 响应代码 - 已完成请求的 HTTP 响应代码。

  • 时间 - 开始时间(收到请求时)和结束时间(发送响应时)。

  • 用户代理 - 请求中的 user-agent

  • 内容长度 - 响应中的 content-length

向应用程序中添加跟踪筛选器 (Tomcat)

对于 Tomcat,请将 <filter> 添加到您项目的 web.xml 文件。使用 fixedName 参数可指定要应用于为传入请求创建的分段的服务名称

例 WEB-INF/web.xml - Tomcat
<filter> <filter-name>AWSXRayServletFilter</filter-name> <filter-class>com.amazonaws.xray.javax.servlet.AWSXRayServletFilter</filter-class> <init-param> <param-name>fixedName</param-name> <param-value>MyApp</param-value> </init-param> </filter> <filter-mapping> <filter-name>AWSXRayServletFilter</filter-name> <url-pattern>*</url-pattern> </filter-mapping>

为您的应用程序添加跟踪筛选器 (Spring)

对于 Spring,请将 Filter 添加到您的 WebConfig 类。将分段名称作为字符串传递到 AWSXRayServletFilter 构造函数。

例 src/main/java/myapp/ .java-sp WebConfig ring
package myapp; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Bean; import javax.servlet.Filter; import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter; @Configuration public class WebConfig { @Bean public Filter TracingFilter() { return new AWSXRayServletFilter("Scorekeep"); } }

配置分段命名策略

Amazon X-Ray 使用服务名称来标识您的应用程序,并将其与您的应用程序使用的其他应用程序、数据库、外部 API 和 Amazon 资源区分开来。当 X-Ray 开发工具包为传入请求生成分段时,会将应用程序的服务名称记录在分段的名称字段中。

X-Ray 开发工具包可以用在 HTTP 请求标头中的 hostname 来命名分段。不过,此标头可以伪造,会导致服务地图中出现意料之外的节点。为防止开发工具包由于包含伪造的主机标头的请求而错误地命名分段,必须为传入请求指定一个默认名称。

如果应用程序为多个域的请求提供服务,则可以将开发工具包配置为使用动态命名策略以在分段名称中反映出这一点。动态命名策略允许开发工具包将主机名用于符合预期模式的请求,并将默认名称应用于不符合预期模式的请求。

例如,可能有一款应用程序为发送到三个子域的请求提供服务,分别为 www.example.comapi.example.comstatic.example.com。可以使用格式 *.example.com 的动态命名策略以识别包含不同名称的子域的分段,服务地图上因此会显示三个服务节点。如果应用程序收到包含与该格式不匹配的 hostname 的请求,您将会在服务地图上看到第四个节点,以及您指定的回退名称。

要对所有请求分段使用同一名称,可在初始化 servlet 筛选器时指定应用程序名称,如上一部分中所示。这与SegmentNamingStrategy通过调用SegmentNamingStrategy.fixed()并传递给AWSXRayServletFilter构造函数来创建固定值具有相同的效果。

注意

您可以使用 AWS_XRAY_TRACING_NAME 环境变量覆盖您在代码中定义的默认服务名称。

动态命名策略定义一个主机名应匹配的模式和一个在 HTTP 请求中的主机名与该模式不匹配时要使用的默认名称。要在 Tomcat 中动态命名分段,可使用 dynamicNamingRecognizedHostsdynamicNamingFallbackName 相应地定义模式和默认名称。

例 WEB-INF/web.xml - 带动态命名的 Servlet 筛选器
<filter> <filter-name>AWSXRayServletFilter</filter-name> <filter-class>com.amazonaws.xray.javax.servlet.AWSXRayServletFilter</filter-class> <init-param> <param-name>dynamicNamingRecognizedHosts</param-name> <param-value>*.example.com</param-value> </init-param> <init-param> <param-name>dynamicNamingFallbackName</param-name> <param-value>MyApp</param-value> </init-param> </filter> <filter-mapping> <filter-name>AWSXRayServletFilter</filter-name> <url-pattern>*</url-pattern> </filter-mapping>

对于 Spring,SegmentNamingStrategy通过调用创建一个动态SegmentNamingStrategy.dynamic(),然后将其传递给AWSXRayServletFilter构造函数。

例 src/main/java/myapp/ .java WebConfig-带动态命名的 servlet 过滤器
package myapp; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Bean; import javax.servlet.Filter; import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter; import com.amazonaws.xray.strategy.SegmentNamingStrategy; @Configuration public class WebConfig { @Bean public Filter TracingFilter() { return new AWSXRayServletFilter(SegmentNamingStrategy.dynamic("MyApp", "*.example.com")); } }

使用适用于 Java 的 X-Ray SD Amazon K 追踪 SDK 调用

当您的应用调用 Amazon Web Services 以存储数据、写入队列或发送通知时,适用于 Java 的 X-Ray SDK 会按子分段跟踪下游的调用。在这些服务(例如,Amazon S3 存储桶或 Amazon SQS 队列)中追踪的资源 Amazon Web Services 和访问的资源在 X-Ray 控制台的跟踪地图上显示为下游节点。

当您在生成中包括 aws-sdkaws-sdk-instrumentor 子模块时,适用于 Java 的 X-Ray 开发工具包自动检测所有 Amazon 开发工具包客户端。如果您未包括 Instrumentor 子模块,则可以选择检测一些客户端,同时排除另一些。

要检测单个客户端,请从版本中移除aws-sdk-instrumentor子模块,然后使用该服务的客户端生成器在 Amazon SDK 客户端TracingHandler上添加一个XRayClient

例如,要检测 AmazonDynamoDB 客户端,请将跟踪处理程序传递到 AmazonDynamoDBClientBuilder

例 MyModel.java-DynamoDB 客户端
import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.handlers.TracingHandler; ... public class MyModel { private AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard() .withRegion(Regions.fromName(System.getenv("AWS_REGION"))) .withRequestHandlers(new TracingHandler(AWSXRay.getGlobalRecorder())) .build(); ...

对于所有服务,都可以在 X-Ray 控制台中看到调用的 API 的名称。X-Ray 开发工具包会为一部分服务将信息添加到分段,从而在服务地图中提供更高的粒度。

例如,当使用经过检测的 DynamoDB 客户端发出调用时,对于针对表的调用,开发工具包会将表名称添加到分段中。在控制台中,每个表在服务地图中显示为一个独立的节点,以及没有表作为目标的调用的一般 DynamoDB 节点。

例 对 DynamoDB 进行调用以保存项目的子分段
{ "id": "24756640c0d0978a", "start_time": 1.480305974194E9, "end_time": 1.4803059742E9, "name": "DynamoDB", "namespace": "aws", "http": { "response": { "content_length": 60, "status": 200 } }, "aws": { "table_name": "scorekeep-user", "operation": "UpdateItem", "request_id": "UBQNSO5AEM8T4FDA4RQDEB94OVTDRVV4K4HIRGVJF66Q9ASUAAJG", } }

在您访问指定的资源时,对以下服务的调用会在服务地图中创建额外的节点。没有定向到特定资源的调用,为服务创建了通用节点。

  • Amazon DynamoDB - 表名称

  • Amazon Simple Storage Service - 存储桶和键名称

  • Amazon Simple Queue Service - 队列名称

要 Amazon Web Services 使用 Amazon SDK for Java 2.2 及更高版本检测下游调用,可以在编译配置中省略该aws-xray-recorder-sdk-aws-sdk-v2-instrumentor模块。改为包含 aws-xray-recorder-sdk-aws-sdk-v2 module,然后通过为它们配置 TracingInterceptor 来检测各个客户端。

例 Amazon SDK for Java 2.2 及更高版本-追踪拦截器
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(); //...

使用适用于 Java 的 X-Ray 开发工具包跟踪对下游 HTTP Web 服务的调用

当应用程序对微服务或公共 HTTP API 进行调用时,您可以使用适用于 Java 的 X-Ray 开发工具包的 HttpClient 版本来检测这些调用,并将 API 作为下游服务添加到服务图。

适用于 Java 的 X-Ray SDK 包括DefaultHttpClient一些HttpClientBuilder类,这些类可以用来代替 Apache HttpComponents 等效项来检测传出的 HTTP 调用。

  • com.amazonaws.xray.proxies.apache.http.DefaultHttpClient - org.apache.http.impl.client.DefaultHttpClient

  • com.amazonaws.xray.proxies.apache.http.HttpClientBuilder - org.apache.http.impl.client.HttpClientBuilder

这些库位于 aws-xray-recorder-sdk-apache-http 子模块中。

您可以使用 X-Ray 等效项替换现有的导入语句来检测所有客户端,或者在您初始化客户端以检测特定客户端时使用完全限定名称。

例 HttpClientBuilder
import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; import com.amazonaws.xray.proxies.apache.http.HttpClientBuilder; ... public String randomName() throws IOException { CloseableHttpClient httpclient = HttpClientBuilder.create().build(); HttpGet httpGet = new HttpGet("http://names.example.com/api/"); CloseableHttpResponse response = httpclient.execute(httpGet); try { HttpEntity entity = response.getEntity(); InputStream inputStream = entity.getContent(); ObjectMapper mapper = new ObjectMapper(); Map<String, String> jsonMap = mapper.readValue(inputStream, Map.class); String name = jsonMap.get("name"); EntityUtils.consume(entity); return name; } finally { response.close(); } }

在您检测对下游 Web API 的调用时,适用于 Java 的 X-Ray 开发工具包会使用有关 HTTP 请求和响应的信息记录子分段。X-Ray 使用子分段为远程 API 生成推断分段。

例 下游 HTTP 调用的子分段
{ "id": "004f72be19cddc2a", "start_time": 1484786387.131, "end_time": 1484786387.501, "name": "names.example.com", "namespace": "remote", "http": { "request": { "method": "GET", "url": "https://names.example.com/" }, "response": { "content_length": -1, "status": 200 } } }
例 下游 HTTP 调用的推断分段
{ "id": "168416dc2ea97781", "name": "names.example.com", "trace_id": "1-62be1272-1b71c4274f39f122afa64eab", "start_time": 1484786387.131, "end_time": 1484786387.501, "parent_id": "004f72be19cddc2a", "http": { "request": { "method": "GET", "url": "https://names.example.com/" }, "response": { "content_length": -1, "status": 200 } }, "inferred": true }

使用适用于 Java 的 X-Ray 开发工具包跟踪 SQL 查询

SQL 拦截器

通过将适用于 Java 的 X-Ray 开发工具包 JDBC 拦截程序添加到数据源配置来检测 SQL 数据库查询。

  • PostgreSQLcom.amazonaws.xray.sql.postgres.TracingInterceptor

  • MySQLcom.amazonaws.xray.sql.mysql.TracingInterceptor

这些拦截程序分别位于 aws-xray-recorder-sql-postgres 和 aws-xray-recorder-sql-mysql 子模块中。它们实现 org.apache.tomcat.jdbc.pool.JdbcInterceptor 并与 Tomcat 连接池兼容。

注意

为了安全起见,SQL 拦截程序不在子分段中记录 SQL 查询本身。

对于 Spring,在属性文件中添加拦截程序并使用 Spring Boot 的 DataSourceBuilder 构建数据源。

src/main/java/resources/application.properties - ostgreSQL JDBC 拦截器
spring.datasource.continue-on-error=true spring.jpa.show-sql=false spring.jpa.hibernate.ddl-auto=create-drop spring.datasource.jdbc-interceptors=com.amazonaws.xray.sql.postgres.TracingInterceptor spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL94Dialect
src/main/java/myapp/WebConfig.java - 数据源
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import javax.servlet.Filter; import javax.sql.DataSource; import java.net.URL; @Configuration @EnableAutoConfiguration @EnableJpaRepositories("myapp") public class RdsWebConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource() { logger.info("Initializing PostgreSQL datasource"); return DataSourceBuilder.create() .driverClassName("org.postgresql.Driver") .url("jdbc:postgresql://" + System.getenv("RDS_HOSTNAME") + ":" + System.getenv("RDS_PORT") + "/ebdb") .username(System.getenv("RDS_USERNAME")) .password(System.getenv("RDS_PASSWORD")) .build(); } ... }

对于 Tomcat,使用对适用于 Java 类的 X-Ray 开发工具包的引用来对 JDBC 数据源调用 setJdbcInterceptors

src/main/myapp/model.java - 数据源
import org.apache.tomcat.jdbc.pool.DataSource; ... DataSource source = new DataSource(); source.setUrl(url); source.setUsername(user); source.setPassword(password); source.setDriverClassName("com.mysql.jdbc.Driver"); source.setJdbcInterceptors("com.amazonaws.xray.sql.mysql.TracingInterceptor;");

Tomcat JDBC 数据源库包含在适用于 Java 的 X-Ray 开发工具包中,但您可以将其声明为提供的依赖关系来记载您将会使用它。

pom.xml - JDBC 数据源
<dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> <version>8.0.36</version> <scope>provided</scope> </dependency>

原生 SQL 跟踪装饰器

  • aws-xray-recorder-sdk-sql 添加到依赖项。

  • 装饰您的数据库数据源、连接或语句。

    dataSource = TracingDataSource.decorate(dataSource) connection = TracingConnection.decorate(connection) statement = TracingStatement.decorateStatement(statement) preparedStatement = TracingStatement.decoratePreparedStatement(preparedStatement, sql) callableStatement = TracingStatement.decorateCallableStatement(callableStatement, sql)

使用适用于 Java 的 X-Ray 开发工具包生成自定义子分段

子分段可为跟踪的分段扩展为了给请求提供服务而已完成的工作的详细信息。每次使用已检测的客户端进行调用时,X-Ray 开发工具包在子分段中记录生成的信息。您可以创建其他子分段来分组其他子分段,来度量某个代码段的性能如何,或是来记录注释和元数据。

要管理子分段,请使用 beginSubsegmentendSubsegment 方法。

例 GameModel.java-自定义子细分
import com.amazonaws.xray.AWSXRay; ... public void saveGame(Game game) throws SessionNotFoundException { // wrap in subsegment Subsegment subsegment = AWSXRay.beginSubsegment("Save Game"); try { // check session String sessionId = game.getSession(); if (sessionModel.loadSession(sessionId) == null ) { throw new SessionNotFoundException(sessionId); } mapper.save(game); } catch (Exception e) { subsegment.addException(e); throw e; } finally { AWSXRay.endSubsegment(); } }

在此示例中,子分段中的代码使用会话模型上的方法从 DynamoDB 加载游戏会话,并使用的 Dynam Amazon SDK for Java oDB 映射器保存游戏。在子分段中包装此代码将调用控制台跟踪视图中 Save Game 子分段的 DynamoDB 子项。

如果子分段中的代码引发了检查异常,将其包装在 try 代码块中并在 AWSXRay.endSubsegment() 代码块中调用 finally 以确保始终结束子分段。如果子分段未结束,则父分段无法完成,不发送到 X-Ray。

对于未引发检查异常的代码,可以将代码传递到 AWSXRay.CreateSubsegment 作为 lambda 函数。

例 子分段 Lambda 函数
import com.amazonaws.xray.AWSXRay; AWSXRay.createSubsegment("getMovies", (subsegment) -> { // function code });

当您在分段或者其他子分段中创建子分段时,适用于 Java 的 X-Ray 开发工具包将为其生成 ID 并记录开始时间和结束时间。

例 包含元数据的子分段
"subsegments": [{ "id": "6f1605cd8a07cb70", "start_time": 1.480305974194E9, "end_time": 1.4803059742E9, "name": "Custom subsegment for UserModel.saveUser function", "metadata": { "debug": { "test": "Metadata string from UserModel.saveUser" } },

对于异步和多线程编程,必须手动将子分段传递给 endSubsegment() 方法以确保其正确关闭,因为在异常执行期间可能会修改 X-Ray 上下文。如果异步子分段在其父分段之前关闭,则此方法将会自动整个分段流式传输到 X-Ray 进程守护程序。

例 异步子分段
@GetMapping("/api") public ResponseEntity<?> api() { CompletableFuture.runAsync(() -> { Subsegment subsegment = AWSXRay.beginSubsegment("Async Work"); try { Thread.sleep(3000); } catch (InterruptedException e) { subsegment.addException(e); throw e; } finally { AWSXRay.endSubsegment(subsegment); } }); return ResponseEntity.ok().build(); }

使用适用于 Java 的 X-Ray 开发工具包,将注释和元数据添加到分段

您可以使用注释和元数据来记录有关请求、环境或应用程序的其他信息。可以将注释和元数据添加到 X-Ray 开发工具包创建的分段或您创建的自定义子分段。

注释是带字符串、数字或布尔值的键值对。系统会对注释编制索引,以便与筛选表达式一起使用。使用注释记录要用于对控制台中的跟踪进行分组的数据或在调用 GetTraceSummaries API 时使用的数据。

元数据是可以具有任何类型值的键-值对,包括对象和列表,但没有编制索引,无法与筛选条件表达式一起使用。使用元数据记录要存储在跟踪中但不需要用于搜索跟踪的其他数据。

除了注释和元数据之外,您还可以在分段上记录用户 ID 字符串。用户 ID 记录在分段的单独字段中,并且不会为其编制索引以用于搜索。

使用适用于 Java 的 X-Ray 开发工具包记录注释

使用注释记录有关要为其编制索引以进行搜索的分段和子分段的信息。

注释要求
  • 密钥-X-Ray 注释的密钥最多可以包含 500 个字母数字字符。不能使用除下划线符号 (_) 之外的空格或符号。

  • -X-Ray 注释的值最多可以包含 1,000 个 Unicode 字符。

  • 注释的数量-每条轨迹最多可以使用 50 个注释。

记录注释
  1. AWSXRay 获取对当前分段或子分段的引用。

    import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.entities.Segment; ... Segment document = AWSXRay.getCurrentSegment();

    或者

    import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.entities.Subsegment; ... Subsegment document = AWSXRay.getCurrentSubsegment();
  2. 调用带有字符串键和布尔值、数字值或字符串值的 putAnnotation

    document.putAnnotation("mykey", "my value");

开发工具包将注释以键-值对的形式记录在分段文档的 annotations 对象中。使用相同键调用两次 putAnnotation 将覆盖同一分段或子分段上之前记录的值。

要查找具有带特定值的注释的跟踪,请在annotations.key筛选表达式中使用 关键字。

src/main/java/scorekeep/GameModel.java - 注释和元数据
import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.entities.Segment; import com.amazonaws.xray.entities.Subsegment; ... public void saveGame(Game game) throws SessionNotFoundException { // wrap in subsegment Subsegment subsegment = AWSXRay.beginSubsegment("## GameModel.saveGame"); try { // check session String sessionId = game.getSession(); if (sessionModel.loadSession(sessionId) == null ) { throw new SessionNotFoundException(sessionId); } Segment segment = AWSXRay.getCurrentSegment(); subsegment.putMetadata("resources", "game", game); segment.putAnnotation("gameid", game.getId()); mapper.save(game); } catch (Exception e) { subsegment.addException(e); throw e; } finally { AWSXRay.endSubsegment(); } }

使用适用于 Java 的 X-Ray 开发工具包记录元数据

使用元数据记录有关您无需为其编制索引以进行搜索的分段或子分段的信息。元数据值可以是字符串、数字、布尔值或可序列化为 JSON 对象或数组的任何对象。

记录元数据
  1. AWSXRay 获取对当前分段或子分段的引用。

    import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.entities.Segment; ... Segment document = AWSXRay.getCurrentSegment();

    或者

    import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.entities.Subsegment; ... Subsegment document = AWSXRay.getCurrentSubsegment();
  2. 调用带有字符串命名空间、字符串键和布尔值、数字值、字符串值或对象值的 putMetadata

    document.putMetadata("my namespace", "my key", "my value");

    或者

    调用仅带有键和值的 putMetadata

    document.putMetadata("my key", "my value");

如果您没有指定命名空间,则开发工具包将使用 default。使用相同键调用两次 putMetadata 将覆盖同一分段或子分段上之前记录的值。

src/main/java/scorekeep/GameModel.java - 注释和元数据
import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.entities.Segment; import com.amazonaws.xray.entities.Subsegment; ... public void saveGame(Game game) throws SessionNotFoundException { // wrap in subsegment Subsegment subsegment = AWSXRay.beginSubsegment("## GameModel.saveGame"); try { // check session String sessionId = game.getSession(); if (sessionModel.loadSession(sessionId) == null ) { throw new SessionNotFoundException(sessionId); } Segment segment = AWSXRay.getCurrentSegment(); subsegment.putMetadata("resources", "game", game); segment.putAnnotation("gameid", game.getId()); mapper.save(game); } catch (Exception e) { subsegment.addException(e); throw e; } finally { AWSXRay.endSubsegment(); } }

使用适用于 Java 的 X-Ray 开发工具包记录用户 ID

记录请求分段上的用户 ID 以标识发送请求的用户。

记录用户 ID
  1. AWSXRay 获取对当前分段的引用。

    import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.entities.Segment; ... Segment document = AWSXRay.getCurrentSegment();
  2. 使用发送请求的用户的字符串 ID 调用 setUser

    document.setUser("U12345");

您可以在控制器中调用 setUser 以便在应用程序开始处理请求后立即记录用户 ID。如果您只打算使用分段来设置用户 ID,可以在单个行中链接这些调用。

src/main/java/scorekeeep/ .java — 用户 ID MoveController
import com.amazonaws.xray.AWSXRay; ... @RequestMapping(value="/{userId}", method=RequestMethod.POST) public Move newMove(@PathVariable String sessionId, @PathVariable String gameId, @PathVariable String userId, @RequestBody String move) throws SessionNotFoundException, GameNotFoundException, StateNotFoundException, RulesException { AWSXRay.getCurrentSegment().setUser(userId); return moveFactory.newMove(sessionId, gameId, userId, move); }

要查找用户 ID 的跟踪,请在user筛选表达式中使用 关键字。

Amazon X-Ray 适用于 Java 的 X-Ray SDK 的指标

本主题介绍 Amazon X-Ray 命名空间、指标和维度。您可以使用适用于 Java 的 X-Ray SDK 从您收集的 X-Ray 区段中发布未采样的亚马逊 CloudWatch 指标。这些指标来自分段的开始和结束时间以及错误、故障和限制状态标志。使用这些指标可暴露子分段里的重试和依赖项问题。

CloudWatch 本质上是一个指标存储库。指标是中的基本概念 CloudWatch ,代表一组按时间排序的数据点。您(或 Amazon Web Services)将指标数据点发布到其中, CloudWatch 并将有关这些数据点的统计数据作为一组有序的时间序列数据进行检索。

指标通过名称、命名空间以及一个或多个维度进行唯一定义。每个数据点都有一个时间戳和一个可选的度量单位。当请求统计数据时,返回的数据流根据命名空间、指标名称和维度加以识别。

有关的更多信息 CloudWatch,请参阅 Amazon CloudWatch 用户指南

X-Ray CloudWatch 指标

ServiceMetrics/SDK 命名空间包括以下指标。

指标 可用统计数据 描述 单位

Latency

平均、最小、最大、计数

开始时间和结束时间之间的差异。平均、最小和最大都描述操作延迟。计数描述调用次数。

毫秒

ErrorRate

平均、总计

导致错误的失败请求率,显示 4xx Client Error 状态码。

百分比

FaultRate

平均、总计

导致故障的失败跟踪率,显示 5xx Server Error 状态码。

百分比

ThrottleRate

平均、总计

返回 429 状态码的受限制跟踪率。这是 ErrorRate 指标的子集。

百分比

OkRate

平均、总计

导致 OK 状态码的被跟踪请求率。

百分比

X 射线 CloudWatch 尺寸

您可以用下表中的维度来优化针对经 X-Ray 检测的 Java 应用程序返回的指标。

维度 描述

ServiceType

服务类型,例如 AWS::EC2::InstanceNONE(如果为未知)。

ServiceName

服务的规范名称。

启用 X-Ray CloudWatch 指标

使用以下过程在已检测的 Java 应用程序中启用跟踪指标。

配置跟踪指标
  1. aws-xray-recorder-sdk-metrics 包添加为 Maven 依赖项。有关更多信息,请参阅 适用于 Java Submodules 的 X-Ray 开发工具包

  2. 启用新的 MetricsSegmentListener() 作为全局记录器构建的一部分。

    例 src/com/myapp/web/Startup.java
    import com.amazonaws.xray.AWSXRay; import com.amazonaws.xray.AWSXRayRecorderBuilder; import com.amazonaws.xray.plugins.EC2Plugin; import com.amazonaws.xray.plugins.ElasticBeanstalkPlugin; import com.amazonaws.xray.strategy.sampling.LocalizedSamplingStrategy; @Configuration public class WebConfig { ... static { AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder .standard() .withPlugin(new EC2Plugin()) .withPlugin(new ElasticBeanstalkPlugin()) .withSegmentListener(new MetricsSegmentListener()); URL ruleFile = WebConfig.class.getResource("/sampling-rules.json"); builder.withSamplingStrategy(new LocalizedSamplingStrategy(ruleFile)); AWSXRay.setGlobalRecorder(builder.build()); } }
  3. 部署 CloudWatch 代理以使用亚马逊弹性计算云 (Amazon EC2)、亚马逊弹性容器服务 (Amazon ECS) 或亚马逊 Elastic Kubernetes Service(亚马逊 EKS)收集指标:

  4. 将 SDK 配置为与 CloudWatch 代理通信。默认情况下,SDK 通过地址127.0.0.1与 CloudWatch 代理进行通信。您可以通过将环境变量或 Java 属性设置为 address:port 来配置备用地址。

    例 环境变量
    AWS_XRAY_METRICS_DAEMON_ADDRESS=address:port
    例 Java 属性
    com.amazonaws.xray.metrics.daemonAddress=address:port
验证配置
  1. 登录 Amazon Web Services Management Console 并打开 CloudWatch 控制台,网址为 https://console.aws.amazon.com/cloudwatch/

  2. 打开指标选项卡以观察指标的情况。

  3. (可选)在 CloudWatch 控制台的日志选项卡上,打开ServiceMetricsSDK日志组。查找与主机指标相匹配的日志流,然后确认日志消息。

在多线程应用程序中的线程之间传递分段上下文

在您的应用程序中创建新线程时,AWSXRayRecorder 不会维护对当前分段或子分段实体的引用。如果您在新话题中使用经过检测的客户端,SDK 会尝试写入不存在的区段,从而导致 SegmentNotFoundException.

为避免在开发过程中抛出异常,您可以为记录器配置一个ContextMissingStrategy提醒它记录错误的。您可以使用代码配置策略 SetContextMissingStrategy,也可以使用环境变量系统属性配置等效选项。

解决错误的一种方法是使用新分段:在您启动线程时调用 beginSegment,并在您将其关闭时调用 endSegment。如果您正在检测并非为响应 HTTP 请求而运行的代码,例如在您的应用程序启动时运行的代码,这很适合。

如果您使用多个线程来处理传入请求,您可以将当前分段或子分段传递到新线程,并将其提供给全局记录器。这样可以确保对于新线程中记录的信息,相关联的分段与针对该请求记录的其余信息的关联分段相同。一旦分段在新线程中可用,即可执行任何可使用 segment.run(() -> { ... }) 方法访问该分段的上下文的可运行。

有关示例,请参阅 在工作线程中使用检测的客户端

使用 X-Ray 进行异步编程

适用于 Java 的 X-Ray SDK 可以在异步 Java 程序中使用SegmentContextExecutors。 SegmentContextExecutor 实现了 Executor 接口,这意味着它可以传递到 a CompletableFuture的所有异步操作中。这样可以确保任何异步操作都将在其上下文中使用正确的分段执行。

例 示例 App.java:传递 SegmentContextExecutor 给 CompletableFuture
DynamoDbAsyncClient client = DynamoDbAsyncClient.create(); AWSXRay.beginSegment(); // ... client.getItem(request).thenComposeAsync(response -> { // If we did not provide the segment context executor, this request would not be traced correctly. return client.getItem(request2); }, SegmentContextExecutors.newSegmentContextExecutor());

包含 Spring 以及适用于 Java 的 X-Ray 开发工具包的 AOP

本主题介绍如何使用 X-Ray 开发工具包和 Spring Framework 检测应用程序,而不更改其核心逻辑。这意味着现在有一种非侵入性的方法可以检测远程运行的应用程序。 Amazon

配置 Spring

您可以使用 Maven 或 Gradle 将 Spring 配置为使用 AOP 检测您的应用程序。

如果您使用 Maven 来生成应用程序,则在 pom.xml 文件中添加以下依赖项。

<dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-xray-recorder-sdk-spring</artifactId> <version>2.11.0</version> </dependency>

对于 Gradle,在 build.gradle 文件中添加以下依赖项。

compile 'com.amazonaws:aws-xray-recorder-sdk-spring:2.11.0'

配置 Spring Boot

除了上一节中介绍的 Spring 依赖项,如果您使用的是 Spring Boot,如果尚位在类路径上,请添加以下依赖项。

Maven:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.5.2</version> </dependency>

Gradle:

compile 'org.springframework.boot:spring-boot-starter-aop:2.5.2'

向您的应用程序添加跟踪筛选器

Filter 添加到 WebConfig 类。将分段名称作为字符串传递到 AWSXRayServletFilter 构造函数。有关跟踪筛选器和检测传入请求的更多信息,请参阅 使用适用于 Java 的 X-Ray 开发工具包跟踪传入请求

例 src/main/java/myapp/ .java-sp WebConfig ring
package myapp; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Bean; import javax.servlet.Filter; import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter; @Configuration public class WebConfig { @Bean public Filter TracingFilter() { return new AWSXRayServletFilter("Scorekeep"); } }

Jakarta 支持

Spring 6 企业版使用 Jakarta 而非 Java。为支持这一全新命名空间,X-Ray 创建出位于其自己 Jakarta 命名空间里的类的并行集。

对于筛选器类,将 javax 替换为 jakarta。配置分段命名策略时,如下所示,在命名策略类名称前添加 jakarta

package myapp; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Bean; import jakarta.servlet.Filter; import com.amazonaws.xray.jakarta.servlet.AWSXRayServletFilter; import com.amazonaws.xray.strategy.jakarta.SegmentNamingStrategy; @Configuration public class WebConfig { @Bean public Filter TracingFilter() { return new AWSXRayServletFilter(SegmentNamingStrategy.dynamic("Scorekeep")); } }

对代码添加注释或实现接口

您的类必须使用 @XRayEnabled 注释添加注释,或实现 XRayTraced 接口。这将告知 AOP 系统包装受影响类的函数以进行 X-Ray 检测。

激活应用程序中的 X-Ray

要激活应用程序中的 X-Ray 跟踪,您的代码必须通过覆盖以下方法来扩展抽象类 BaseAbstractXRayInterceptor

  • generateMetadata - 此函数允许对附加到当前函数跟踪的元数据进行自定义。默认情况下,执行函数的类名将记录在元数据中。如果您需要其他信息,则可添加更多数据。

  • xrayEnabledClasses - 此函数为空,并且应保持此状态。它用作告知拦截程序要包装的方法的指示的主机。通过指定使用要跟踪的 @XRayEnabled 添加注释的类来定义指示。以下指示语句告知拦截程序包装使用 @XRayEnabled 注释添加注释的所有控制器 bean。

    @Pointcut(“@within(com.amazonaws.xray.spring.aop.XRayEnabled) && bean(*Controller)”)

如果项目使用的是 Spring Data JPA,请考虑从 AbstractXRayInterceptor 而非 BaseAbstractXRayInterceptor 进行扩展。

示例

以下代码扩展抽象类 BaseAbstractXRayInterceptor

@Aspect @Component public class XRayInspector extends BaseAbstractXRayInterceptor { @Override protected Map<String, Map<String, Object>> generateMetadata(ProceedingJoinPoint proceedingJoinPoint, Subsegment subsegment) throws Exception { return super.generateMetadata(proceedingJoinPoint, subsegment); } @Override @Pointcut("@within(com.amazonaws.xray.spring.aop.XRayEnabled) && bean(*Controller)") public void xrayEnabledClasses() {} }

以下代码是一个将由 X-Ray 检测的类。

@Service @XRayEnabled public class MyServiceImpl implements MyService { private final MyEntityRepository myEntityRepository; @Autowired public MyServiceImpl(MyEntityRepository myEntityRepository) { this.myEntityRepository = myEntityRepository; } @Transactional(readOnly = true) public List<MyEntity> getMyEntities(){ try(Stream<MyEntity> entityStream = this.myEntityRepository.streamAll()){ return entityStream.sorted().collect(Collectors.toList()); } } }

如果您已正确配置您的应用程序,则应看到应用程序的完整调用堆栈(从控制器向下至服务调用),如以下控制台屏幕截图所示。


        完整的调用堆栈。