

# AWS Lambda에서 Java 코드 계측
<a name="java-tracing"></a>

Lambda는 AWS X-Ray와 통합되어 Lambda 애플리케이션을 추적, 디버깅 및 최적화할 수 있습니다. Lambda 함수와 기타 AWS 서비스를 포함할 수 있는 애플리케이션의 리소스를 탐색할 때 X-Ray를 사용하여 요청을 추적할 수 있습니다.

추적 데이터를 X-Ray로 전송하려면 다음 두 SDK 라이브러리 중 하나를 사용할 수 있습니다.
+ [AWS Distro for OpenTelemetry(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/) - 서버리스 모범 사례를 구현하고 개발자 속도를 높이기 위한 개발자 도구 키트입니다.

각 SDK는 텔레메트리 데이터를 X-Ray 서비스로 전송하는 방법을 제공합니다. X-Ray를 사용하여 애플리케이션의 성능 지표를 확인하고, 필터링하고, 인사이트를 얻어 문제와 최적화 기회를 식별할 수 있습니다.

**중요**  
X-Ray와 Powertools for AWS Lambda SDK는 AWS에서 제공하는 긴밀하게 통합된 계측 솔루션의 일부입니다. ADOT Lambda Layer는 일반적으로 더 많은 데이터를 수집하는 추적 계측기에 대한 전체 업계 표준의 일부이지만 모든 사용 사례에 적합하지는 않을 수 있습니다. 어떤 솔루션을 사용하든 X-Ray에서 엔드 투 엔드 추적 기능을 구현할 수 있습니다. 둘 중 하나를 선택하는 방법에 대해 자세히 알아보려면 [AWS Distro for Open Telemetry와 X-Ray SDK 중에서 선택하기](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 함수가 간접 호출되고 Embedded Metric Format을 사용하여 로그 및 지표를 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 함수가 간접 호출되고 Embedded Metric Format을 사용하여 로그 및 지표를 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 Constructor](https://docs.aws.amazon.com/cdk/api/v1/java/aws_cdk.aws_lambda.html)와 [ApiGatewayv2 Constructor](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는 OTel SDK를 사용하여 원격 측정 데이터를 수집하는 데 필요한 모든 것을 패키징할 수 있는 완전 관리형 Lambda [계층](chapter-layers.md)을 제공합니다. 이 계층을 사용하면 모든 함수 코드를 수정하지 않고도 Lambda 함수를 계측할 수 있습니다. 계층을 구성하여 OTel의 사용자 지정 초기화를 수행할 수도 있습니다. 자세한 내용은 ADOT 설명서의 [Lambda에서 ADOT 컬렉터에 대한 사용자 지정 구성](https://aws-otel.github.io/docs/getting-started/lambda#custom-configuration-for-the-adot-collector-on-lambda)을 참조하세요.

Java 런타임의 경우 두 계층 중에서 선택하여 사용할 수 있습니다.
+ **AWS ADOT Java용 관리형 Lambda 계층(자동 계측 에이전트)** - 이 계층은 시작 시 함수 코드를 자동으로 변환하여 추적 데이터를 수집합니다. ADOT Java 에이전트와 함께 이 계층을 사용하는 방법에 대한 자세한 지침은 ADOT 설명서의 [AWS Distro for OpenTelemetry Lambda Support for Java (Auto-instrumentation Agent)(Java용 Distro for OpenTelemetry Lambda Support(자동 계측 에이전트))](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java-auto-instr)를 참조하세요.
+ **AWS ADOT Java용 관리형 Lambda 계층** - 이 계층은 Lambda 함수에 대한 기본 제공 계측도 제공하지만, OTel SDK를 초기화하려면 몇 가지 코드를 직접 변경해야 합니다. 이 계층을 사용하는 방법에 대한 자세한 지침은 ADOT 설명서의 [AWS Distro for OpenTelemetry Lambda Support for Java(Java용 Distro for OpenTelemetry Lambda Support)](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를 빌드 구성에 추가합니다. 다음 예에서는 AWS SDK for Java 2.x 클라이언트의 자동 계측을 활성화하는 라이브러리를 포함하는 Gradle 빌드 구성을 보여줍니다.

**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. Lambda 콘솔의 [함수 페이지](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)는 애플리케이션 및 모든 구성 요소에 대한 정보를 보여줍니다. 다음 예제에서는 2개의 함수가 있는 애플리케이션을 보여줍니다. 기본 함수는 이벤트를 처리하고 때로는 오류를 반환합니다. 맨 위의 두 번째 함수는 첫 번째의 로그 그룹에 나타나는 오류를 처리하고 AWS SDK를 사용하여 X-Ray, Amazon Simple Storage Service(Amazon S3), Amazon CloudWatch Logs를 호출합니다.

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


X-Ray는 애플리케이션에 대한 모든 요청을 추적하지 않습니다. X-Ray는 모든 요청의 대표 샘플을 여전히 제공하면서 추적이 효율적으로 수행되도록 샘플링 알고리즘을 적용합니다. 샘플링 요율은 초당 요청이 1개이며 추가 요청의 5퍼센트입니다. 함수에 대해 X-Ray 샘플링 요율을 구성할 수 없습니다.

X-Ray에서 *추적*은 하나 이상의 *서비스*에서 처리되는 요청에 대한 정보를 기록합니다. Lambda는 각 추적에 대해 2개의 세그먼트를 기록하고, 이에 따라 서비스 그래프에 2개의 노드가 생성됩니다. 다음 이미지에서는 이 두 노드를 강조 표시합니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/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/ko_kr/lambda/latest/dg/images/V2_sandbox_images/my-function-2-v1.png)


이 예제에서는 3개의 하위 세그먼트를 표시하도록 `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) 섹션을 참조하세요.

**가격 책정**  
X-Ray 추적을 AWS 프리 티어의 일부로서 특정 한도까지 매월 무료로 사용할 수 있습니다. 해당 한도를 초과하면 추적 저장 및 검색에 대한 X-Ray 요금이 부과됩니다. 자세한 내용은 [AWS X-Ray 요금](https://aws.amazon.com/xray/pricing/)을 참조하십시오.

## 계층에 런타임 종속성 저장(X-Ray SDK)
<a name="java-tracing-layers"></a>

X-Ray SDK를 사용하여 AWS SDK 클라이언트를 계측하는 경우 함수 코드와 배포 패키지가 상당히 커질 수 있습니다. 함수 코드를 업데이트할 때마다 런타임 종속성을 업로드하지 않으려면 X-Ray SDK를 [Lambda 계층](chapter-layers.md)에 패키징합니다.

다음 예에서는 AWS SDK for Java 및 Java용 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) – Lambda를 사용하여 주문을 처리하는 방법을 보여주는 Java 함수입니다. 이 함수는 사용자 지정 입력 이벤트 객체를 정의 및 역직렬화하고 AWS SDK를 사용하며 로깅을 출력하는 방법을 보여줍니다.
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) – 단위 테스트 및 변수 로깅 구성을 사용하는 최소한의 Java 함수 모음입니다.
+ [java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Amazon API Gateway, Amazon SQS 및 Amazon Kinesis와 같은 다양한 서비스의 이벤트를 처리하는 방법에 대한 스켈레톤 코드가 포함된 Java 함수 모음입니다. 이러한 함수는 최신 버전의 [aws-lambda-java-events](java-package.md) 라이브러리(3.0.0 이상)를 사용합니다. 이러한 예는 AWS SDK를 종속 항목으로 요구하지 않습니다.
+ [s3-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/s3-java) – Amazon S3의 알림 이벤트를 처리하고 JCL(Java Class Library)을 사용하여 업로드된 이미지 파일의 썸네일을 생성하는 Java 함수입니다.
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) - Lambda 계층을 사용하여 코어 함수 코드와 별도로 종속성을 패키징하는 방법을 보여주는 Java 함수입니다.

모든 샘플 애플리케이션은 Lambda 함수에 대해 활성 추적을 사용하도록 설정되어 있습니다. `s3-java` 애플리케이션은 AWS SDK for Java 2.x 클라이언트의 자동 계측, 테스트를 위한 세그먼트 관리, 사용자 지정 하위 세그먼트 및 런타임 종속성을 저장하기 위한 Lambda 계층의 사용을 보여줍니다.