AWS Lambda 함수 로깅(Java) - AWS Lambda

AWS Lambda 함수 로깅(Java)

Lambda 함수는 CloudWatch Logs 로그 그룹과 함께 제공되며, 함수의 각 인스턴스에 대한 로그 스트림을 포함합니다. 런타임은 각 호출에 관한 세부 정보를 로그 스트림에 전송하며, 함수 코드에서 로그 및 그 외 출력을 중계합니다.

함수 코드의 로그를 출력하려면 java.lang.System에서 메서드를 사용하거나, stdout 또는 stderr에 쓰는 로깅 모듈을 사용합니다. aws-lambda-java-core 라이브러리는 컨텍스트 객체에서 액세스 할 수 있는 LambdaLogger라는 로거 클래스를 제공합니다. 로거 클래스는 여러 줄 로그를 지원합니다.

다음 예제에서는 컨텍스트 객체가 제공하는 LambdaLogger 로거를 사용합니다.

예 Handler.java

// Handler value: example.Handler public class Handler implements RequestHandler<Object, String>{ Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Override public String handleRequest(Object event, Context context) { LambdaLogger logger = context.getLogger(); String response = new String("SUCCESS"); // log execution details logger.log("ENVIRONMENT VARIABLES: " + gson.toJson(System.getenv())); logger.log("CONTEXT: " + gson.toJson(context)); // process event logger.log("EVENT: " + gson.toJson(event)); return response; } }

예 로그 형식

START RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Version: $LATEST ENVIRONMENT VARIABLES: { "_HANDLER": "example.Handler", "AWS_EXECUTION_ENV": "AWS_Lambda_java8", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "512", ... } CONTEXT: { "memoryLimit": 512, "awsRequestId": "6bc28136-xmpl-4365-b021-0ce6b2e64ab0", "functionName": "java-console", ... } EVENT: { "records": [ { "messageId": "19dd0b57-xmpl-4ac1-bd88-01bbb068cb78", "receiptHandle": "MessageReceiptHandle", "body": "Hello from SQS!", ... } ] } END RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 REPORT RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Duration: 198.50 ms Billed Duration: 200 ms Memory Size: 512 MB Max Memory Used: 90 MB Init Duration: 524.75 ms

Java 런타임은 각 호출에 대해 START, ENDREPORT 줄을 로깅합니다. 보고서 행은 다음과 같은 세부 정보를 제공합니다.

보고서 로그

  • RequestId – 호출의 고유한 요청 ID입니다.

  • 지속시간 – 함수의 핸들러 메서드가 이벤트를 처리하는 데 걸린 시간입니다.

  • 청구 기간 – 호출에 대해 청구된 시간입니다.

  • 메모리 크기– 함수에 할당된 메모리 양입니다.

  • 사용된 최대 메모리 – 함수에서 사용한 메모리 양입니다.

  • 초기화 기간 – 제공된 첫 번째 요청의 경우 런타임이 핸들러 메서드 외부에서 함수를 로드하고 코드를 실행하는 데 걸린 시간입니다.

  • XRAY TraceId – 추적된 요청의 경우 AWS X-Ray 추적 ID입니다.

  • 세그먼트 ID – 추적된 요청의 경우 X-Ray 세그먼트 ID입니다.

  • 샘플링 – 추적된 요청의 경우 샘플링 결과입니다.

Lambda 콘솔, CloudWatch Logs 콘솔 또는 명령줄에서 로그를 볼 수 있습니다.

AWS Management 콘솔에서 로그 보기

함수 구성 페이지에서 함수를 테스트할 때 Lambda 콘솔에 로그 출력이 표시됩니다. 모든 호출에 대한 로그를 보려면 CloudWatch Logs 콘솔을 사용합니다.

Lambda 함수의 로그를 보려면

  1. CloudWatch 콘솔의 로그 페이지를 엽니다.

  2. 함수(/aws/lambda/function-name)에 대한 로그 그룹을 선택합니다.

  3. 목록에서 첫 번째 스트림을 선택합니다.

각 로그 스트림은 함수의 인스턴스에 해당합니다. 새 스트림은 함수를 업데이트할 때, 그리고 여러 동시 호출을 처리하기 위해 추가 인스턴스가 생성될 때 나타납니다. 특정 호출에 대한 로그를 찾으려면 X-Ray로 함수를 계측하고 추적의 요청 및 로그 스트림에 대한 세부 정보를 기록합니다. 로그 및 추적을 X-Ray와 상호 연관시키는 샘플 애플리케이션의 경우 AWS Lambda용 오류 처리자 샘플 애플리케이션 단원을 참조하십시오.

AWS CLI 사용

명령줄에서 호출에 대한 로그를 가져오려면 --log-type 옵션을 사용하십시오. 호출에서 base64로 인코딩된 로그를 최대 4KB까지 포함하는 LogResult 필드가 응답에 포함됩니다.

$ aws lambda invoke --function-name my-function out --log-type Tail { "StatusCode": 200, "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...", "ExecutedVersion": "$LATEST" }

base64 유틸리티를 사용하면 로그를 디코딩할 수 있습니다.

$ aws lambda invoke --function-name my-function out --log-type Tail \ --query 'LogResult' --output text | base64 -d START RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Version: $LATEST "AWS_SESSION_TOKEN": "AgoJb3JpZ2luX2VjELj...", "_X_AMZN_TRACE_ID": "Root=1-5d02e5ca-f5792818b6fe8368e5b51d50;Parent=191db58857df8395;Sampled=0"",ask/lib:/opt/lib", END RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 REPORT RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Duration: 79.67 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 73 MB

base64는 Linux, macOS 및 Ubuntu on Windows에서 사용할 수 있습니다. macOS의 경우, 명령은 base64 -D입니다.

명령줄에서 전체 로그 이벤트를 가져오기 위해 앞의 예와 같이 함수 출력에 로그 스트림 이름을 포함할 수 있습니다. 다음 예제 스크립트는 my-function이라는 함수를 호출하고 마지막 5개 로그 이벤트를 다운로드합니다.

예 get-logs.sh 스크립트

이 예에서는 my-function이 로그 스트림 ID를 반환해야 합니다.

#!/bin/bash aws lambda invoke --function-name my-function --payload '{"key": "value"}' out sed -i'' -e 's/"//g' out sleep 15 aws logs get-log-events --log-group-name /aws/lambda/my-function --log-stream-name $(cat out) --limit 5

스크립트는 sed를 사용하여 출력 파일에서 따옴표를 제거하고, 로그를 사용할 수 있는 시간을 허용하기 위해 15초 동안 대기합니다. 출력에는 Lambda의 응답과 get-log-events 명령의 출력이 포함됩니다.

$ ./get-logs.sh { "StatusCode": 200, "ExecutedVersion": "$LATEST" } { "events": [ { "timestamp": 1559763003171, "message": "START RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf Version: $LATEST\n", "ingestionTime": 1559763003309 }, { "timestamp": 1559763003173, "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tENVIRONMENT VARIABLES\r{\r \"AWS_LAMBDA_FUNCTION_VERSION\": \"$LATEST\",\r ...", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003173, "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tEVENT\r{\r \"key\": \"value\"\r}\n", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003218, "message": "END RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\n", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003218, "message": "REPORT RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\tDuration: 26.73 ms\tBilled Duration: 100 ms \tMemory Size: 128 MB\tMax Memory Used: 75 MB\t\n", "ingestionTime": 1559763018353 } ], "nextForwardToken": "f/34783877304859518393868359594929986069206639495374241795", "nextBackwardToken": "b/34783877303811383369537420289090800615709599058929582080" }

로그 삭제

함수를 삭제해도 로그 그룹이 자동으로 삭제되지 않습니다. 로그를 무기한 저장하지 않으려면 로그 그룹을 삭제하거나 로그가 자동으로 삭제되는 보존 기간을 구성하십시오.

Log4j 2 및 SLF4J를 사용한 고급 로깅

로그 출력을 사용자 지정하고, 단위 테스트 중 로깅을 지원하고, AWS SDK 호출을 기록하려면 Apache Log4j 2를 SLF4J와 함께 사용합니다. Log4j는 Java 프로그램을 위한 로깅 라이브러리로서, 로그 수준을 구성하고 appender 라이브러리를 사용할 수 있도록 합니다. SLF4J는 facade 라이브러리로서, 함수 코드를 변경하지 않고 사용하는 라이브러리를 변경할 수 있도록 합니다.

함수의 로그에 요청 ID를 추가하려면 aws-lambda-java-log4j2 라이브러리의 appender를 사용합니다. 다음 예제에서는 모든 로그에 타임스탬프와 요청 ID를 추가하는 Log4j 2 구성 파일을 보여 줍니다.

src/main/resources/log4j2.xml – appender 구성

<Configuration status="WARN"> <Appenders> <Lambda name="Lambda"> <PatternLayout> <pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1} - %m%n</pattern> </PatternLayout> </Lambda> </Appenders> <Loggers> <Root level="INFO"> <AppenderRef ref="Lambda"/> </Root> <Logger name="software.amazon.awssdk" level="WARN" /> <Logger name="software.amazon.awssdk.request" level="DEBUG" /> </Loggers> </Configuration>

이 구성에서는 각 행 앞에 날짜, 시간, 요청 ID, 로그 수준 및 클래스 이름이 추가됩니다.

예 appender를 사용한 로그 형식

START RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Version: $LATEST 2020-03-18 08:52:43 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 INFO Handler - ENVIRONMENT VARIABLES: { "_HANDLER": "example.Handler", "AWS_EXECUTION_ENV": "AWS_Lambda_java8", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "512", ... } 2020-03-18 08:52:43 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 INFO Handler - CONTEXT: { "memoryLimit": 512, "awsRequestId": "6bc28136-xmpl-4365-b021-0ce6b2e64ab0", "functionName": "java-console", ... }

SLF4J는 Java 코드에 로깅하기 위한 facade 라이브러리입니다. 함수 코드에서 SLF4J 로거 팩토리를 사용하여 info()warn()과 같은 로그 수준에 대한 메서드로 로거를 가져옵니다. 빌드 구성에서 로깅 라이브러리와 SLF4J 어댑터를 클래스 경로에 포함합니다. 빌드 구성에서 라이브러리를 변경하면 함수 코드를 변경하지 않고 로거 유형을 변경할 수 있습니다. SLF4J는 Java용 SDK에서 로그를 캡처하는 데 필요합니다.

다음 예제에서 핸들러 클래스는 SLF4J를 사용하여 로거를 검색합니다.

src/main/java/example/Handler.java – SLF4J를 사용한 로깅

import org.slf4j.Logger; import org.slf4j.LoggerFactory; // Handler value: example.Handler public class Handler implements RequestHandler<SQSEvent, String>{ private static final Logger logger = LoggerFactory.getLogger(Handler.class); Gson gson = new GsonBuilder().setPrettyPrinting().create(); LambdaAsyncClient lambdaClient = LambdaAsyncClient.create(); @Override public String handleRequest(SQSEvent event, Context context) { String response = new String(); // call Lambda API logger.info("Getting account settings"); CompletableFuture<GetAccountSettingsResponse> accountSettings = lambdaClient.getAccountSettings(GetAccountSettingsRequest.builder().build()); // log execution details logger.info("ENVIRONMENT VARIABLES: {}", gson.toJson(System.getenv())); ...

빌드 구성은 Lambda appender 및 SLF4J 어댑터에 대한 런타임 종속성을 사용하고 Log4J 2에 대한 구현 종속성을 사용합니다.

build.gradle – 종속성 로깅

dependencies { implementation platform('software.amazon.awssdk:bom:2.10.73') implementation platform('com.amazonaws:aws-xray-recorder-sdk-bom:2.4.0') implementation 'software.amazon.awssdk:lambda' implementation 'com.amazonaws:aws-xray-recorder-sdk-core' implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk-core' implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk-v2' implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk-v2-instrumentor' implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' implementation 'com.amazonaws:aws-lambda-java-events:3.1.0' implementation 'com.google.code.gson:gson:2.8.6' implementation 'org.apache.logging.log4j:log4j-api:2.13.0' implementation 'org.apache.logging.log4j:log4j-core:2.13.0' runtimeOnly 'org.apache.logging.log4j:log4j-slf4j18-impl:2.13.0' runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.2.0' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0' }

테스트를 위해 로컬에서 코드를 실행하면 Lambda 로거가 있는 컨텍스트 객체를 사용할 수 없으며 Lambda appender가 사용할 요청 ID가 없습니다. 테스트 구성에 대한 예는 다음 단원의 샘플 애플리케이션을 참조하십시오.

샘플 로깅 코드

이 안내서의 GitHub 리포지토리에는 다양한 로깅 구성의 사용을 보여주는 샘플 애플리케이션이 들어 있습니다. 각 샘플 애플리케이션에는 간편한 배포 및 정리를 위한 스크립트, AWS SAM 템플릿 및 지원 리소스가 포함되어 있습니다.

Java의 샘플 Lambda 애플리케이션

  • blank-java – Lambda의 Java 라이브러리, 로깅, 환경 변수, 계층, AWS X-Ray 추적, 단위 테스트 및 AWS SDK를 사용하는 방법을 보여주는 Java 함수입니다.

  • java-basic – 단위 테스트 및 변수 로깅 구성을 사용하는 최소한의 Java 함수입니다.

  • java-events – AWS SDK를 Amazon API Gateway 같은 종속성으로 요구하지 않는 이벤트 유형과 함께 aws-lambda-java-events 라이브러리를 사용하는 최소한의 Java 함수입니다.

  • java-events-v1sdk – 종속성(예: Amazon Simple Storage Service, Amazon DynamoDB 및 Amazon Kinesis)으로 AWS SDK를 요구하지 않는 이벤트 유형과 함께 aws-lambda-java-events 라이브러리를 사용하는 최소한의 Java 함수입니다.

  • s3-java – Amazon S3의 알림 이벤트를 처리하고 JCL(Java Class Library)을 사용하여 업로드된 이미지 파일의 썸네일을 생성하는 Java 함수입니다.

java-basic 샘플 애플리케이션은 로깅 테스트를 지원하는 최소 로깅 구성을 보여 줍니다. 핸들러 코드는 컨텍스트 객체가 제공하는 LambdaLogger 로거를 사용합니다. 애플리케이션은 테스트를 위해 Log4j 2 로거와 함께 LambdaLogger 인터페이스를 구현하는 사용자 지정 TestLogger 클래스를 사용하며, AWS SDK와의 호환성을 위한 facade로 SLF4J를 사용합니다. 로깅 라이브러리는 배포 패키지를 작게 유지하기 위해 빌드 출력에서 제외되어 있습니다.

blank-java 샘플 애플리케이션은 AWS SDK 로깅 및 Lambda Log4j 2 appender를 사용한 기본 구성으로 빌드되어 있습니다. 각 행에 호출 요청 ID를 추가하는 사용자 지정 appender와 함께 Log4j 2를 Lambda에서 사용합니다.