

# 在 AWS Lambda 中检测 Java 代码
<a name="java-tracing"></a>

Lambda 与 AWS X-Ray 集成，以帮助您跟踪、调试和优化 Lambda 应用程序。您可以在某个请求遍历应用程序中的资源（其中可能包括 Lambda 函数和其他 AWS 服务）时，使用 X-Ray 跟踪该请求。

要将跟踪数据发送到 X-Ray，您可以使用以下两个软件开发工具包 (SDK) 库之一：
+ [适用于 OpenTelemetry 的 AWS 发行版 (ADOT)](https://aws.amazon.com/otel) – 一种安全、可供生产、支持 AWS 的 OpenTelemetry (OTel) SDK 的分发版本。
+ [AWS X-Ray SDK for Java](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-java.html) – 用于生成跟踪数据并将其发送到 X-Ray 的 SDK
+ [Powertools for AWS Lambda（Java）](https://docs.aws.amazon.com/powertools/java/latest/)– 一个开发人员工具包，用于实施无服务器最佳实践并提高开发人员速度。

每个开发工具包均提供了将遥测数据发送到 X-Ray 服务的方法。然后，您可以使用 X-Ray 查看、筛选和获得对应用程序性能指标的洞察，从而发现问题和优化机会。

**重要**  
X-Ray 和 Powertools for AWS Lambda SDK 是 AWS 提供的紧密集成的分析解决方案的一部分。ADOT Lambda Layers 是全行业通用的跟踪分析标准的一部分，该标准通常会收集更多数据，但可能不适用于所有使用案例。您可以使用任一解决方案在 X-Ray 中实现端到端跟踪。要了解有关如何在两者之间进行选择的更多信息，请参阅[在 AWS Distro for Open Telemetry 和 X-Ray 开发工具包之间进行选择](https://docs.aws.amazon.com/xray/latest/devguide/xray-instrumenting-your-app.html#xray-instrumenting-choosing)。

**Topics**
+ [将 Powertools for AWS Lambda（Java）和 AWS SAM 用于跟踪](#java-tracing-sam)
+ [将 Powertools for AWS Lambda（Java）和 AWS CDK 用于跟踪](#java-tracing-cdk)
+ [使用 ADOT 分析您的 Java 函数](#java-adot)
+ [使用 X-Ray SDK 分析您的 Java 函数](#java-xray-sdk)
+ [使用 Lambda 控制台激活跟踪](#java-tracing-console)
+ [使用 Lambda API 激活跟踪](#java-tracing-api)
+ [使用 CloudFormation 激活跟踪](#java-tracing-cloudformation)
+ [解释 X-Ray 跟踪](#java-tracing-interpretation)
+ [在层中存储运行时依赖项 (X-Ray SDK)](#java-tracing-layers)
+ [示例应用程序中的 X-Ray 跟踪 (X-Ray SDK)](#java-tracing-samples)

## 将 Powertools for AWS Lambda（Java）和 AWS SAM 用于跟踪
<a name="java-tracing-sam"></a>

请按照以下步骤使用 AWS SAM，通过集成的 [Powertools for AWS Lambda（Java）](https://docs.powertools.aws.dev/lambda-java)模块来下载、构建和部署示例 Hello World Java 应用程序。此应用程序实现了基本的 API 后端，并使用 Powertools 发送日志、指标和跟踪。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，Lambda 函数会使用嵌入式指标格式向 CloudWatch 调用、发送日志和指标，并向 AWS X-Ray 发送跟踪。该函数将返回一条 `hello world` 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ Java 11 或更高版本
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。如果您使用的是旧版本的 AWS SAM CLI，请参阅[升级 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署示例 AWS SAM 应用程序**

1. 使用 Hello World Java 模板初始化该应用程序。

   ```
   sam init --app-template hello-world-powertools-java --name sam-app --package-type Zip --runtime java11 --no-tracing
   ```

1. 构建应用程序。

   ```
   cd sam-app && sam build
   ```

1. 部署应用程序。

   ```
   sam deploy --guided
   ```

1. 按照屏幕上的提示操作。要在交互式体验中接受提供的默认选项，请按 `Enter`。
**注意**  
对于 **HelloWorldFunction 可能没有定义授权，确定执行此操作吗？**，确保输入 `y`。

1. 获取已部署应用程序的 URL：

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. 调用 API 端点：

   ```
   curl -X GET <URL_FROM_PREVIOUS_STEP>
   ```

   如果成功，您将会看到如下响应：

   ```
   {"message":"hello world"}
   ```

1. 要获取该函数的跟踪信息，请运行 [sam traces](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html)。

   ```
   sam traces
   ```

   该跟踪输出类似于以下示例：

   ```
   New XRay Service Graph
     Start time: 2025-02-03 14:31:48+01:00
     End time: 2025-02-03 14:31:48+01:00
     Reference Id: 0 - (Root) AWS::Lambda - sam-app-HelloWorldFunction-y9Iu1FLJJBGD - Edges: []
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 5.587
     Reference Id: 1 - client - sam-app-HelloWorldFunction-y9Iu1FLJJBGD - Edges: [0]
      Summary_statistics:
        - total requests: 0
        - ok count(2XX): 0
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0
   
   XRay Event [revision 3] at (2025-02-03T14:31:48.500000) with id (1-63dd0cc4-3c869dec72a586875da39777) and duration (5.603s)
    - 5.587s - sam-app-HelloWorldFunction-y9Iu1FLJJBGD [HTTP: 200]
    - 4.053s - sam-app-HelloWorldFunction-y9Iu1FLJJBGD
      - 1.181s - Initialization
      - 4.037s - Invocation
        - 1.981s - ## handleRequest
          - 1.840s - ## getPageContents
      - 0.000s - Overhead
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   sam delete
   ```

## 将 Powertools for AWS Lambda（Java）和 AWS CDK 用于跟踪
<a name="java-tracing-cdk"></a>

请按照以下步骤使用 AWS CDK，通过集成的 [Powertools for AWS Lambda（Java）](https://docs.powertools.aws.dev/lambda-java)模块来下载、构建和部署示例 Hello World Java 应用程序。此应用程序实现了基本的 API 后端，并使用 Powertools 发送日志、指标和跟踪。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，Lambda 函数会使用嵌入式指标格式向 CloudWatch 调用、发送日志和指标，并向 AWS X-Ray 发送跟踪。该函数将返回一条 hello world 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ Java 11 或更高版本
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS CDK 版本 2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。如果您使用的是旧版本的 AWS SAM CLI，请参阅[升级 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署示例 AWS CDK 应用程序**

1. 为您的新应用程序创建一个项目目录。

   ```
   mkdir hello-world
   cd hello-world
   ```

1. 初始化该应用程序。

   ```
   cdk init app --language java
   ```

1. 使用以下命令创建 Maven 项目：

   ```
   mkdir app
   cd app
   mvn archetype:generate -DgroupId=helloworld -DartifactId=Function -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
   ```

1. 打开 `hello-world\app\Function` 目录中的 `pom.xml`，并将现有代码替换为以下代码，其中包括 Powertools 的依赖项和 Maven 插件。

   ```
   <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>helloworld</groupId>
     <artifactId>Function</artifactId>
     <packaging>jar</packaging>
     <version>1.0-SNAPSHOT</version>
     <name>Function</name>
     <url>http://maven.apache.org</url>
   <properties>
       <maven.compiler.source>11</maven.compiler.source>
       <maven.compiler.target>11</maven.compiler.target>
       <log4j.version>2.17.2</log4j.version>
   </properties>
       <dependencies>
           <dependency>
               <groupId>junit</groupId>
               <artifactId>junit</artifactId>
               <version>3.8.1</version>
               <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>software.amazon.lambda</groupId>
               <artifactId>powertools-tracing</artifactId>
               <version>1.3.0</version>
           </dependency>
           <dependency>
               <groupId>software.amazon.lambda</groupId>
               <artifactId>powertools-metrics</artifactId>
               <version>1.3.0</version>
           </dependency>
           <dependency>
               <groupId>software.amazon.lambda</groupId>
               <artifactId>powertools-logging</artifactId>
               <version>1.3.0</version>
           </dependency>
           <dependency>
               <groupId>com.amazonaws</groupId>
               <artifactId>aws-lambda-java-core</artifactId>
               <version>1.2.2</version>
           </dependency>
           <dependency>
               <groupId>com.amazonaws</groupId>
               <artifactId>aws-lambda-java-events</artifactId>
               <version>3.11.1</version>
           </dependency>
     </dependencies>
   <build>
       <plugins>
           <plugin>
               <groupId>org.codehaus.mojo</groupId>
               <artifactId>aspectj-maven-plugin</artifactId>
               <version>1.14.0</version>
               <configuration>
                   <source>${maven.compiler.source}</source>
                   <target>${maven.compiler.target}</target>
                   <complianceLevel>${maven.compiler.target}</complianceLevel>
                   <aspectLibraries>
                       <aspectLibrary>
                           <groupId>software.amazon.lambda</groupId>
                           <artifactId>powertools-tracing</artifactId>
                       </aspectLibrary>
                       <aspectLibrary>
                           <groupId>software.amazon.lambda</groupId>
                           <artifactId>powertools-metrics</artifactId>
                       </aspectLibrary>
                       <aspectLibrary>
                           <groupId>software.amazon.lambda</groupId>
                           <artifactId>powertools-logging</artifactId>
                       </aspectLibrary>
                   </aspectLibraries>
               </configuration>
               <executions>
                   <execution>
                       <goals>
                           <goal>compile</goal>
                       </goals>
                   </execution>
               </executions>
           </plugin>
           <plugin>
                   <groupId>org.apache.maven.plugins</groupId>
                   <artifactId>maven-shade-plugin</artifactId>
                   <version>3.4.1</version>
                   <executions>
                       <execution>
                           <phase>package</phase>
                           <goals>
                               <goal>shade</goal>
                           </goals>
                           <configuration>
                               <transformers>
                                   <transformer
                                           implementation="com.github.edwgiz.maven_shade_plugin.log4j2_cache_transformer.PluginsCacheFileTransformer">
                                   </transformer>
                               </transformers>
                               <createDependencyReducedPom>false</createDependencyReducedPom>
                               <finalName>function</finalName>
   
                           </configuration>
                       </execution>
                   </executions>
                   <dependencies>
                       <dependency>
                           <groupId>com.github.edwgiz</groupId>
                           <artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId>
                           <version>2.15</version>
                       </dependency>
                   </dependencies>
           </plugin>
       </plugins>
   </build>
   </project>
   ```

1. 创建 `hello-world\app\src\main\resource` 目录并为日志配置创建 `log4j.xml`。

   ```
   mkdir -p src/main/resource
   cd src/main/resource
   touch log4j.xml
   ```

1. 打开 `log4j.xml` 并添加以下代码。

   ```
   <?xml version="1.0" encoding="UTF-8"?>
   <Configuration>
       <Appenders>
           <Console name="JsonAppender" target="SYSTEM_OUT">
               <JsonTemplateLayout eventTemplateUri="classpath:LambdaJsonLayout.json" />
           </Console>
       </Appenders>
       <Loggers>
           <Logger name="JsonLogger" level="INFO" additivity="false">
               <AppenderRef ref="JsonAppender"/>
           </Logger>
           <Root level="info">
               <AppenderRef ref="JsonAppender"/>
           </Root>
       </Loggers>
   </Configuration>
   ```

1. 打开 `hello-world\app\Function\src\main\java\helloworld` 目录中的 `App.java`，并将现有代码替换为以下代码。这是适用于 Lambda 函数的代码。

   ```
   package helloworld;
   
   import java.io.BufferedReader;
   import java.io.IOException;
   import java.io.InputStreamReader;
   import java.net.URL;
   import java.util.HashMap;
   import java.util.Map;
   import java.util.stream.Collectors;
   
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
   import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
   import org.apache.logging.log4j.LogManager;
   import org.apache.logging.log4j.Logger;
   import software.amazon.lambda.powertools.logging.Logging;
   import software.amazon.lambda.powertools.metrics.Metrics;
   import software.amazon.lambda.powertools.tracing.CaptureMode;
   import software.amazon.lambda.powertools.tracing.Tracing;
   
   import static software.amazon.lambda.powertools.tracing.CaptureMode.*;
   
   /**
    * Handler for requests to Lambda function.
    */
   public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
       Logger log = LogManager.getLogger(App.class);
   
   
       @Logging(logEvent = true)
       @Tracing(captureMode = DISABLED)
       @Metrics(captureColdStart = true)
       public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
           Map<String, String> headers = new HashMap<>();
           headers.put("Content-Type", "application/json");
           headers.put("X-Custom-Header", "application/json");
   
           APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent()
                   .withHeaders(headers);
           try {
               final String pageContents = this.getPageContents("https://checkip.amazonaws.com");
               String output = String.format("{ \"message\": \"hello world\", \"location\": \"%s\" }", pageContents);
   
               return response
                       .withStatusCode(200)
                       .withBody(output);
           } catch (IOException e) {
               return response
                       .withBody("{}")
                       .withStatusCode(500);
           }
       }
       @Tracing(namespace = "getPageContents")
       private String getPageContents(String address) throws IOException {
           log.info("Retrieving {}", address);
           URL url = new URL(address);
           try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
               return br.lines().collect(Collectors.joining(System.lineSeparator()));
           }
       }
   }
   ```

1. 打开 `hello-world\src\main\java\com\myorg` 目录中的 `HelloWorldStack.java`，并将现有代码替换为以下代码。此代码将使用 [Lambda 构造函数](https://docs.aws.amazon.com/cdk/api/v1/java/aws_cdk.aws_lambda.html)和 [ApiGatewayv2 构造函数](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigatewayv2-readme.html)创建 REST API 和 Lambda 函数。

   ```
   package com.myorg;
   
   import software.amazon.awscdk.*;
   import software.amazon.awscdk.services.apigatewayv2.alpha.*;
   import software.amazon.awscdk.services.apigatewayv2.integrations.alpha.HttpLambdaIntegration;
   import software.amazon.awscdk.services.apigatewayv2.integrations.alpha.HttpLambdaIntegrationProps;
   import software.amazon.awscdk.services.lambda.Code;
   import software.amazon.awscdk.services.lambda.Function;
   import software.amazon.awscdk.services.lambda.FunctionProps;
   import software.amazon.awscdk.services.lambda.Runtime;
   import software.amazon.awscdk.services.lambda.Tracing;
   import software.amazon.awscdk.services.logs.RetentionDays;
   import software.amazon.awscdk.services.s3.assets.AssetOptions;
   import software.constructs.Construct;
   
   import java.util.Arrays;
   import java.util.List;
   
   import static java.util.Collections.singletonList;
   import static software.amazon.awscdk.BundlingOutput.ARCHIVED;
   
   public class HelloWorldStack extends Stack {
       public HelloWorldStack(final Construct scope, final String id) {
           this(scope, id, null);
       }
   
       public HelloWorldStack(final Construct scope, final String id, final StackProps props) {
           super(scope, id, props);
   
           List<String> functionPackagingInstructions = Arrays.asList(
                   "/bin/sh",
                   "-c",
                   "cd Function " +
                           "&& mvn clean install " +
                           "&& cp /asset-input/Function/target/function.jar /asset-output/"
           );
           BundlingOptions.Builder builderOptions = BundlingOptions.builder()
                   .command(functionPackagingInstructions)
                   .image(Runtime.JAVA_11.getBundlingImage())
                   .volumes(singletonList(
                           // Mount local .m2 repo to avoid download all the dependencies again inside the container
                           DockerVolume.builder()
                                   .hostPath(System.getProperty("user.home") + "/.m2/")
                                   .containerPath("/root/.m2/")
                                   .build()
                   ))
                   .user("root")
                   .outputType(ARCHIVED);
   
           Function function = new Function(this, "Function", FunctionProps.builder()
                   .runtime(Runtime.JAVA_11)
                   .code(Code.fromAsset("app", AssetOptions.builder()
                           .bundling(builderOptions
                                   .command(functionPackagingInstructions)
                                   .build())
                           .build()))
                   .handler("helloworld.App::handleRequest")
                   .memorySize(1024)
                   .tracing(Tracing.ACTIVE)
                   .timeout(Duration.seconds(10))
                   .logRetention(RetentionDays.ONE_WEEK)
                   .build());
   
           HttpApi httpApi = new HttpApi(this, "sample-api", HttpApiProps.builder()
                   .apiName("sample-api")
                   .build());
   
           httpApi.addRoutes(AddRoutesOptions.builder()
                   .path("/")
                   .methods(singletonList(HttpMethod.GET))
                   .integration(new HttpLambdaIntegration("function", function, HttpLambdaIntegrationProps.builder()
                           .payloadFormatVersion(PayloadFormatVersion.VERSION_2_0)
                           .build()))
                   .build());
   
           new CfnOutput(this, "HttpApi", CfnOutputProps.builder()
                   .description("Url for Http Api")
                   .value(httpApi.getApiEndpoint())
                   .build());
       }
   }
   ```

1. 打开 `hello-world` 目录中的 `pom.xml`，并将现有代码替换为以下代码。

   ```
   <?xml version="1.0" encoding="UTF-8"?>
   <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
            xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
       <modelVersion>4.0.0</modelVersion>
   
       <groupId>com.myorg</groupId>
       <artifactId>hello-world</artifactId>
       <version>0.1</version>
   
       <properties>
           <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
           <cdk.version>2.70.0</cdk.version>
           <constructs.version>[10.0.0,11.0.0)</constructs.version>
           <junit.version>5.7.1</junit.version>
       </properties>
   
       <build>
           <plugins>
               <plugin>
                   <groupId>org.apache.maven.plugins</groupId>
                   <artifactId>maven-compiler-plugin</artifactId>
                   <version>3.8.1</version>
                   <configuration>
                       <source>1.8</source>
                       <target>1.8</target>
                   </configuration>
               </plugin>
   
               <plugin>
                   <groupId>org.codehaus.mojo</groupId>
                   <artifactId>exec-maven-plugin</artifactId>
                   <version>3.0.0</version>
                   <configuration>
                       <mainClass>com.myorg.HelloWorldApp</mainClass>
                   </configuration>
               </plugin>
           </plugins>
       </build>
   
       <dependencies>
           <!-- AWS Cloud Development Kit -->
           <dependency>
               <groupId>software.amazon.awscdk</groupId>
               <artifactId>aws-cdk-lib</artifactId>
               <version>${cdk.version}</version>
           </dependency>
           <dependency>
               <groupId>software.constructs</groupId>
               <artifactId>constructs</artifactId>
               <version>${constructs.version}</version>
           </dependency>
           <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter</artifactId>
             <version>${junit.version}</version>
             <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>software.amazon.awscdk</groupId>
               <artifactId>apigatewayv2-alpha</artifactId>
               <version>${cdk.version}-alpha.0</version>
           </dependency>
           <dependency>
               <groupId>software.amazon.awscdk</groupId>
               <artifactId>apigatewayv2-integrations-alpha</artifactId>
               <version>${cdk.version}-alpha.0</version>
           </dependency>
       </dependencies>
   </project>
   ```

1. 确保您位于 `hello-world` 目录中然后部署应用程序。

   ```
   cdk deploy
   ```

1. 获取已部署应用程序的 URL：

   ```
   aws cloudformation describe-stacks --stack-name HelloWorldStack --query 'Stacks[0].Outputs[?OutputKey==`HttpApi`].OutputValue' --output text
   ```

1. 调用 API 端点：

   ```
   curl -X GET <URL_FROM_PREVIOUS_STEP>
   ```

   如果成功，您将会看到如下响应：

   ```
   {"message":"hello world"}
   ```

1. 要获取该函数的跟踪信息，请运行 [sam traces](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html)。

   ```
   sam traces
   ```

   该跟踪输出类似于以下示例：

   ```
   New XRay Service Graph
     Start time: 2025-02-03 14:59:50+00:00
     End time: 2025-02-03 14:59:50+00:00
     Reference Id: 0 - (Root) AWS::Lambda - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: [1]
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0.924
     Reference Id: 1 - AWS::Lambda::Function - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: []
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0.016
     Reference Id: 2 - client - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: [0]
      Summary_statistics:
        - total requests: 0
        - ok count(2XX): 0
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0
   
   XRay Event [revision 1] at (2025-02-03T14:59:50.204000) with id (1-63dd2166-434a12c22e1307ff2114f299) and duration (0.924s)
    - 0.924s - sam-app-HelloWorldFunction-YBg8yfYtOc9j [HTTP: 200]
    - 0.016s - sam-app-HelloWorldFunction-YBg8yfYtOc9j
      - 0.739s - Initialization
      - 0.016s - Invocation
        - 0.013s - ## lambda_handler
          - 0.000s - ## app.hello
      - 0.000s - Overhead
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   cdk destroy
   ```

## 使用 ADOT 分析您的 Java 函数
<a name="java-adot"></a>

ADOT 提供完全托管式 Lambda [层](chapter-layers.md)，这些层使用 OTel SDK，将收集遥测数据所需的一切内容打包起来。通过使用此层，您可以在不必修改任何函数代码的情况下，对您的 Lambda 函数进行分析。您还可以将您的层配置为对 OTel 进行自定义初始化。有关更多信息，请参阅 ADOT 文档中的[适用于 Lambda 上的 ADOT 收集器的自定义配置](https://aws-otel.github.io/docs/getting-started/lambda#custom-configuration-for-the-adot-collector-on-lambda)。

对于 Java 运行时，您可以在两个层之间选择使用：
+ **适用于 ADOT Java 的 AWS 托管式 Lambda 层（自动分析代理）**- 此层将在启动时自动转换您的函数代码，以收集跟踪数据。有关如何与 ADOT Java 代理配合使用此层的详细说明，请参阅[适用于 OpenTelemetry 的 AWS 发行版对于 Java 的 Lambda 支持（自动分析代理）](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java-auto-instr)。
+ **适用于 ADOT Java 的 AWS 托管式 Lambda 层** - 此层还可为 Lambda 函数提供内置分析，但其需要手动对代码进行一些更改，才能初始化 OTel SDK。有关如何使用此层的详细说明，请参阅 ADOT 文档中的[适用于 OpenTelemetry 的 AWS 发行版对于 Java 的 Lambda 支持](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java)。

## 使用 X-Ray SDK 分析您的 Java 函数
<a name="java-xray-sdk"></a>

要记录关于您的函数对应用程序中的其他资源和服务进行调用的数据，您可以将适用于 Java 的 X-Ray SDK 添加到您的构建配置中。以下示例显示了一种 Gradle 构建配置，其中包括激活 AWS SDK for Java 2.x 客户端自动分析的库。

**Example [build.gradle](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/s3-java/build.gradle) – 跟踪依赖项**  

```
dependencies {
    implementation platform('software.amazon.awssdk:bom:2.16.1')
    implementation platform('com.amazonaws:aws-xray-recorder-sdk-bom:2.11.0')
    ...
    implementation 'com.amazonaws:aws-xray-recorder-sdk-core'
    implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk'
    implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk-v2-instrumentor'
    ...
}
```

在添加正确的依赖项并进行必要的代码更改后，请通过 Lambda 控制台或 API 激活函数配置中的跟踪。

## 使用 Lambda 控制台激活跟踪
<a name="java-tracing-console"></a>

要使用控制台切换 Lambda 函数的活动跟踪，请按照以下步骤操作：

**打开活跃跟踪**

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择函数。

1. 选择 **Configuration**（配置），然后选择 **Monitoring and operations tools**（监控和操作工具）。

1. 在**其他监控工具**下，选择**编辑**。

1. 在 **CloudWatch 应用程序信号和 AWS X-Ray** 下，为 **Lambda 服务跟踪**选择**启用**。

1. 选择**保存**。

## 使用 Lambda API 激活跟踪
<a name="java-tracing-api"></a>

借助 AWS CLI 或 AWS SDK 在 Lambda 函数上配置跟踪，请使用以下 API 操作：
+ [UpdateFunctionConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateFunctionConfiguration.html)
+ [GetFunctionConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_GetFunctionConfiguration.html)
+ [CreateFunction](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html)

以下示例 AWS CLI 命令对名为 **my-function** 的函数启用活跃跟踪。

```
aws lambda update-function-configuration --function-name my-function \
--tracing-config Mode=Active
```

跟踪模式是发布函数版本时版本特定配置的一部分。您无法更改已发布版本上的跟踪模式。

## 使用 CloudFormation 激活跟踪
<a name="java-tracing-cloudformation"></a>

要对 CloudFormation 模板中的 `AWS::Lambda::Function` 资源激活跟踪，请使用 `TracingConfig` 属性。

**Example [function-inline.yml](https://github.com/awsdocs/aws-lambda-developer-guide/blob/master/templates/function-inline.yml) – 跟踪配置**  

```
Resources:
  function:
    Type: [AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html)
    Properties:
      TracingConfig:
        Mode: Active
      ...
```

对于 AWS Serverless Application Model (AWS SAM) `AWS::Serverless::Function` 资源，请使用 `Tracing` 属性。

**Example [template.yml](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-nodejs/template.yml) – 跟踪配置**  

```
Resources:
  function:
    Type: [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      Tracing: Active
      ...
```

## 解释 X-Ray 跟踪
<a name="java-tracing-interpretation"></a>

您的函数需要权限才能将跟踪数据上载到 X-Ray。在 Lambda 控制台中激活跟踪后，Lambda 会将所需权限添加到函数的[执行角色](lambda-intro-execution-role.md)。如果没有，请将 [AWSXRayDaemonWriteAccess](https://console.aws.amazon.com/iam/home#/policies/arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess) 策略添加到执行角色。

在配置活跃跟踪后，您可以通过应用程序观察特定请求。[X-Ray 服务图](https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html#xray-concepts-servicegraph)将显示有关应用程序及其所有组件的信息。以下示例显示了具有两个函数的应用程序。主函数处理事件，有时会返回错误。位于顶部的第二个函数将处理第一个函数的日志组中显示的错误，并使用 AWS SDK 调用 X-Ray、Amazon Simple Storage Service (Amazon S3) 和 Amazon CloudWatch Logs。

![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/sample-errorprocessor-servicemap.png)


X-Ray 无法跟踪对应用程序的所有请求。X-Ray 将应用采样算法确保跟踪有效，同时仍会提供所有请求的一个代表性样本。采样率是每秒 1 个请求和 5% 的其他请求。您无法为函数配置此 X-Ray 采样率。

在 X-Ray 中，*跟踪*记录有关由一个或多个*服务*处理的请求的信息。Lambda 会每个跟踪记录 2 个分段，这些分段将在服务图上创建两个节点。下图突出显示了这两个节点：

![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/xray-servicemap-function.png)


位于左侧的第一个节点表示接收调用请求的 Lambda 服务。第二个节点表示特定的 Lambda 函数。以下示例显示了一个包含这 2 个分段的跟踪。两者都命名为 **my-function**，但其中一个函数具有 `AWS::Lambda` 源，另一个则具有 `AWS::Lambda::Function` 源。如果 `AWS::Lambda` 分段显示错误，则表示 Lambda 服务存在问题。如果 `AWS::Lambda::Function` 分段显示错误，则说明函数存在问题。

![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/V2_sandbox_images/my-function-2-v1.png)


此示例将展开 `AWS::Lambda::Function` 分段，以显示其三个子分段。

**注意**  
AWS 目前正在实施对 Lambda 服务的更改。由于这些更改，您可能会看到 AWS 账户 中不同 Lambda 函数发出的系统日志消息和跟踪分段的结构和内容之间存在细微差异。  
此处显示的示例跟踪说明了旧样式函数分段。以下段落介绍了新旧样式分段之间的差异。  
这些更改将在未来几周内实施，除中国和 GovCloud 区域外，所有 AWS 区域 的函数都将过渡到使用新格式的日志消息和跟踪分段。

旧样式函数分段包含以下子分段：
+ **初始化** – 表示加载函数和运行[初始化代码](foundation-progmodel.md)所花费的时间。此子分段仅对由您的函数的每个实例处理的第一个事件显示。
+ **调用** – 表示执行处理程序代码花费的时间。
+ **开销** – 表示 Lambda 运行时为准备处理下一个事件而花费的时间。

新样式函数分段不包含 `Invocation` 子分段。而是将客户子分段直接附加到函数分段。有关新旧样式函数分段结构的更多信息，请参阅 [了解 X-Ray 跟踪](services-xray.md#services-xray-traces)。

**注意**  
[Lambda SnapStart](snapstart.md) 函数还包括一个 `Restore` 子分段。`Restore` 子分段会显示 Lambda 还原快照、加载运行时和运行任何还原后[运行时挂钩](snapstart-runtime-hooks.md)所花费的时间。恢复快照的过程可能包含在 MicroVM 之外的活动上花费的时间。该时间在 `Restore` 子分段中报告。您无需为在 microVM 之外还原快照所花费的时间付费。

您还可以分析 HTTP 客户端、记录 SQL 查询以及使用注释和元数据创建自定义子段。有关更多信息，请参阅《AWS X-Ray 开发人员指南》**中的 [AWS X-Ray SDK for Java](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-java.html)。

**定价**  
作为 AWS 免费套餐的组成部分，您可以每月免费使用 X-Ray 跟踪，但不能超过一定限制。超出该阈值后，X-Ray 会对跟踪存储和检索进行收费。有关更多信息，请参阅 [AWS X-Ray 定价](https://aws.amazon.com/xray/pricing/)。

## 在层中存储运行时依赖项 (X-Ray SDK)
<a name="java-tracing-layers"></a>

如果您使用 X-Ray 开发工具包来分析AWS开发工具包客户端和您的函数代码，则您的部署程序包可能会变得相当大。为了避免每次更新函数代码时上载运行时依赖项，请将 X-Ray SDK 打包到 [Lambda 层](chapter-layers.md)中。

以下示例显示了存储适用于 Java 的 适用于 Java 的 AWS SDK 和 X-Ray SDK 的 `AWS::Serverless::LayerVersion` 资源。

**Example [template.yml](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-java/template.yml) – 依赖项层**  

```
Resources:
  function:
    Type: [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      CodeUri: build/distributions/blank-java.zip
      Tracing: Active
      Layers:
        - !Ref libs
      ...
  libs:
    Type: [AWS::Serverless::LayerVersion](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-layerversion.html)
    Properties:
      LayerName: blank-java-lib
      Description: Dependencies for the blank-java sample app.
      ContentUri: build/blank-java-lib.zip
      CompatibleRuntimes:
        - java25
```

使用此配置，仅在更改运行时依赖项时您才会更新库层。由于函数部署软件包仅包含您的代码，因此可以帮助缩短上传时间。

为依赖项创建层要求更改构建配置才能在部署之前生成层存档。有关工作示例，请参阅 GitHub 上的 [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) 示例应用程序。

## 示例应用程序中的 X-Ray 跟踪 (X-Ray SDK)
<a name="java-tracing-samples"></a>

本指南的 GitHub 存储库包括演示如何使用 X-Ray 跟踪的示例应用程序。每个示例应用程序都包含用于轻松部署和清理的脚本、一个 AWS SAM 模板和支持资源。

**Java 中的 Lambda 应用程序示例**
+ [example-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/example-java) – 一个 Java 函数，演示如何使用 Lambda 来处理顺序。此函数说明了如何定义和反序列化自定义输入事件对象，如何使用 AWS SDK 和输出日志记录。
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) – 具有单元测试和变量日志记录配置的最小 Java 函数的集合。
+ [java-events](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) – Java 函数的集合，其中包含用于处理来自 Amazon API Gateway、Amazon SQS 和 Amazon Kinesis 等各种服务的事件的框架代码。这些函数使用最新版本的 [aws-lambda-events](java-package.md) 库（3.0.0 及更新版本）。这些示例不需要 AWS 开发工具包作为依赖项。
+ [s3-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/s3-java) – 此 Java 函数可处理来自 Amazon S3 的通知事件，并使用 Java 类库（JCL）从上传的图像文件创建缩略图。
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) – 一个 Java 函数，说明如何使用 Lambda 层将依赖项与核心函数代码分开打包。

所有示例应用程序都为 Lambda 功能启用了活动跟踪。例如，`s3-java` 应用程序显示 AWS SDK for Java 2.x 客户端的自动分析、用于测试的段管理、自定义子段以及使用 Lambda 层存储运行时依赖项。