配置 X-Ray SDK for Java - AWS X-Ray

配置 X-Ray SDK for Java

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

服务插件

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

插件
  • Amazon EC2 - EC2Plugin 会添加实例 ID、可用区和 CloudWatch Logs 组。

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

  • Amazon ECS — ECSPlugin 添加容器 ID。

  • Amazon EKS - EKSPlugin 会添加容器 ID、群集名称、Pod ID 和 CloudWatch Logs 组。

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

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

例 src/main/java/scorekeep/WebConfig.java - Recorder
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()); } }

该 SDK 还使用插件设置为设置分段上的 origin 字段。这指示运行应用程序的 AWS 资源的类型。当使用多个插件时,SDK 会使用以下解析顺序来确定来源:ElasticBeanstalk > EKS > ECS > EC2。

采样规则

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

该 SDK 按照定义的顺序应用自定义规则。如果请求与多个自定义规则匹配,则 SDK 仅应用第一条规则。

注意

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

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

例 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 服务管理。随着您部署更多主机,固定速率会成倍增加,这使得控制记录的数据量变得更加困难。

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

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

例 src/main/java/myapp/WebConfig.java - 记录器配置
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));

日志记录

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

例 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

此特征可以与使用 AWS X-Ray SDK for Java 进行检测的 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 提供的密钥。请参阅 PatternLayout,详细了解 Logback 中的 PatternLayout。

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

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

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

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

跟踪 ID 注入示例

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

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

AWS 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 函数的完整列表,请访问 AWS X-Ray Recorder SDK for Java 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());

环境变量

您可以使用环境变量来配置 X-Ray SDK for Java。SDK 支持以下变量。

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

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

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

    • IGNORE_ERROR— 忽略错误并继续。

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

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

    格式
    • 同一个端口address:port

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

  • AWS_LOG_GROUP - 将日志组的名称设置为与您的应用程序关联的日志组。如果您的日志组使用与您的应用程序相同的 AWS 账户和区域,X-Ray 将使用此指定的日志组自动搜索应用程序的分段数据。有关日志组的更多信息,请参阅使用日志组和日志流

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

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

系统属性

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

  • 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

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