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

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

AWS Lambda 함수 로깅(Java)

AWS Lambda는 자동으로 Lambda 함수를 모니터링하고 로그 항목을 Amazon CloudWatch로 보냅니다. Lambda 함수는 함수의 각 인스턴스에 대한 CloudWatch Logs 로그 그룹 및 로그 스트림과 함께 제공됩니다. Lambda 런타임 환경은 각 간접 호출에 대한 세부 정보와 함수 코드의 기타 출력을 로그 스트림으로 전송합니다. CloudWatch Logs에 대한 자세한 내용은 Amazon CloudWatch 로그를 다음과 같이 사용하기 AWS Lambda 섹션을 참조하세요.

함수 코드에서 로그를 출력하려면 java.lang.System의 메서드 또는 stdout 또는 stderr에 쓰는 로깅 모듈을 사용할 수 있습니다.

로그를 반환하는 함수 생성

함수 코드의 로그를 출력하려면 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 줄을 로깅합니다. 보고서 행은 다음과 같은 세부 정보를 제공합니다.

REPORT 행 데이터 필드
  • RequestId – 호출의 고유한 요청 ID입니다.

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

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

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

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

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

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

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

  • 샘플링 완료(Sampled) – 추적된 요청의 경우 샘플링 결과입니다.

Java에서 Lambda 고급 로깅 제어 사용

함수의 로그를 캡처, 처리 및 사용하는 방법을 더 잘 제어할 수 있도록 지원되는 Java 런타임에 대한 다음의 로깅 옵션을 구성할 수 있습니다.

  • 로그 형식 - 함수 로그의 경우 일반 텍스트와 구조화된 JSON 형식 중에서 선택

  • 로그 수준 - JSON 형식의 로그의 경우, Lambda가 CloudWatch로 전송하는 로그의 세부 수준(ERROR, DEBUG 또는 INFO 등)을 선택

  • 로그 그룹 - 함수가 로그를 보내는 CloudWatch 로그 그룹을 선택

이러한 로깅 옵션에 대한 자세한 내용과 이를 사용하도록 함수를 구성하는 방법에 대한 지침은 Lambda 함수에 대한 고급 로깅 제어 구성을 참조하세요.

Java Lambda 함수에서 로그 형식 및 로그 수준 옵션을 사용하려면 다음 섹션의 지침을 참조하세요.

Java에서 구조화된 JSON 로그 형식 사용

함수의 로그 형식으로 JSON을 선택하면 Lambda는 LambdaLogger 클래스를 사용하여 로그 출력을 구조화된 JSON으로 전송합니다. 각 JSON 로그 객체에는 다음 키가 있는 4개의 키 값 페어가 포함되어 있습니다.

  • "timestamp" - 로그 메시지가 생성된 시간

  • "level" - 메시지에 할당된 로그 수준

  • "message" - 로그 메시지의 내용

  • "AWSrequestId" - 함수 간접 호출의 고유한 요청 ID

사용하는 로깅 방법에 따라 JSON 형식으로 캡처된 함수의 로그 출력에는 추가 키값 페어가 포함될 수도 있습니다.

LambdaLogger 로거를 사용하여 생성한 로그에 수준을 할당하려면 다음 예에서 표시된 것처럼 로깅 명령에 LogLevel 인수를 제공해야 합니다.

예 Java 로깅 코드
LambdaLogger logger = context.getLogger(); logger.log("This is a debug log", LogLevel.DEBUG);

이 예제 코드의 로그 출력은 다음과 같이 CloudWatch Logs에 캡처됩니다.

예 JSON 로그 레코드
{ "timestamp":"2023-11-01T00:21:51.358Z", "level":"DEBUG", "message":"This is a debug log", "AWSrequestId":"93f25699-2cbf-4976-8f94-336a0aa98c6f" }

로그 출력에 수준을 할당하지 않으면 Lambda는 자동으로 수준 INFO를 할당합니다.

코드에서 라이브러리를 사용하여 JSON 구조화된 로그를 생성하는 경우에는 변경할 필요가 없습니다. Lambda는 이미 JSON으로 인코딩된 로그를 이중 인코딩하지 않습니다. JSON 로그 형식을 사용하도록 함수를 구성하더라도 로깅 출력은 사용자가 정의한 JSON 구조로 CloudWatch에 표시됩니다.

Java에서 로그 수준 필터링 사용

AWS Lambda에서 애플리케이션 로그를 로그 수준에 따라 필터링하려면 함수에서 JSON 형식의 로그를 사용해야 합니다. 다음 두 가지 방법으로 이 작업을 달성할 수 있습니다.

로그 수준 필터링을 사용하도록 함수를 구성할 때는 Lambda가 CloudWatch 로그로 전송하기를 원하는 로그 수준을 다음 옵션 중에서 선택해야 합니다.

로그 수준 표준 사용량
TRACE(최대 세부 정보) 코드 실행 경로를 추적하는 데 사용되는 가장 세밀한 정보
DEBUG 시스템 디버깅에 대한 세부 정보
INFO 함수의 정상 작동을 기록하는 메시지
WARN 해결되지 않을 경우 예상치 못한 동작으로 이어질 수 있는 잠재적 오류에 대한 메시지
ERROR 코드가 예상대로 작동하지 못하게 하는 문제에 대한 메시지
FATAL(최소 세부 정보) 응용 프로그램 작동을 중지시키는 심각한 오류에 대한 메시지

Lambda가 함수 로그를 필터링하려면 JSON 로그 출력에 "timestamp" 키 값 쌍도 포함해야 합니다. 시간은 유효한 RFC 3339 타임스탬프 형식으로 지정해야 합니다. 유효한 타임스탬프를 제공하지 않으면 Lambda는 로그에 레벨 INFO를 할당하고 타임스탬프를 추가합니다.

Lambda는 선택한 수준 이하의 로그만 Cloudwatch로 전송합니다. 예를 들어 로그 수준을 WARN으로 구성하면 Lambda는 WARN, ERROR 및 FATAL에 해당하는 로그를 전송합니다.

Log4j2 및 SLF4J를 사용한 고급 로깅

참고

AWS Lambda는 관리형 런타임 또는 기본 컨테이너 이미지에 Log4j2를 포함하지 않습니다. 따라서 CVE-2021-44228, CVE-2021-45046 및 CVE-2021-45105에 설명된 문제에는 영향을 받지 않습니다.

고객 함수가 영향을 받는 Log4j2 버전전을 포함하는 경우, CVE-2021-44228, CVE-2021-45046 및 CVE-2021-45105의 문제를 완화하는 데 도움이 되는 Lambda Java 관리형 런타임기본 컨테이너 이미지에 변경 사항을 적용했습니다. 이 변경의 결과로 Log4J2를 사용하는 고객은 'Transforming org/apache/logging/log4j/core/lookup/JndiLookup (java.net.URLClassLoader@...)'과 유사한 추가 로그 입력 항목을 볼 수 있습니다. Log4J2 출력에서 jndi 매퍼를 참조하는 모든 로그 문자열은 'Patched JndiLookup::lookup()으로 대체됩니다.

이러한 변경과 관계없이 Log4j2가 포함된 함수를 가진 모든 고객은 최신 버전으로 업데이트하는 것이 좋습니다. 특히, 함수에서 aws-lambda-java-log4j2 라이브러리를 사용하는 고객은 버전 1.5.0 이상으로 업데이트하고 함수를 다시 배포해야 합니다. 이 버전은 기본 Log4j2 유틸리티 종속성을 버전 2.17.0 이상으로 업데이트합니다. 업데이트된 aws-lambda-java-log4j2 바이너리는 Maven 리포지토리에서 사용할 수 있으며 소스 코드는 GitHub에서 확인할 수 있습니다.

마지막으로 aws-lambda-java-log4j(v1.0.0 또는 1.0.1)와 관련된 모든 라이브러리는 절대 어떤 상황에서도 사용해서는 안 된다는 점에 유의합니다. 이러한 라이브러리는 2015년에 수명이 끝난 log4j의 버전 1.x와(과) 관련이 있습니다. 라이브러리가 지원되지 않고, 유지 관리되지 않으며, 패치가 적용되지 않으며, 알려져 있는 보안 취약성이 있습니다.

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

함수의 로그에 요청 ID를 추가하려면 aws-lambda-java-log4j2 라이브러리의 appender를 사용합니다.

src/main/resources/log4j2.xml – Appender 구성
<Configuration> <Appenders> <Lambda name="Lambda" format="${env:AWS_LAMBDA_LOG_FORMAT:-TEXT}"> <LambdaTextFormat> <PatternLayout> <pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1} - %m%n </pattern> </PatternLayout> </LambdaTextFormat> <LambdaJSONFormat> <JsonTemplateLayout eventTemplateUri="classpath:LambdaLayout.json" /> </LambdaJSONFormat> </Lambda> </Appenders> <Loggers> <Root level="${env:AWS_LAMBDA_LOG_LEVEL:-INFO}"> <AppenderRef ref="Lambda"/> </Root> <Logger name="software.amazon.awssdk" level="WARN" /> <Logger name="software.amazon.awssdk.request" level="DEBUG" /> </Loggers> </Configuration>

<LambdaTextFormat><LambdaJSONFormat> 태그 아래에 레이아웃을 지정하여 Log4j2 로그가 일반 텍스트 또는 JSON 출력으로 구성되는 방법을 결정할 수 있습니다.

이 예제에서는 텍스트 모드에서 각 행 앞에 날짜, 시간, 요청 ID, 로그 수준 및 클래스 이름이 추가됩니다. JSON 모드에서는 <JsonTemplateLayout>aws-lambda-java-log4j2 라이브러리와 함께 제공되는 구성과 함께 사용됩니다.

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

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

src/main/java/example/HandlerS3.java – SLF4J를 사용한 로깅
package example; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.S3Event; import static org.apache.logging.log4j.CloseableThreadContext.put; public class HandlerS3 implements RequestHandler<S3Event, String>{ private static final Logger logger = LoggerFactory.getLogger(HandlerS3.class); @Override public String handleRequest(S3Event event, Context context) { for(var record : event.getRecords()) { try (var loggingCtx = put("awsRegion", record.getAwsRegion())) { loggingCtx.put("eventName", record.getEventName()); loggingCtx.put("bucket", record.getS3().getBucket().getName()); loggingCtx.put("key", record.getS3().getObject().getKey()); logger.info("Handling s3 event"); } } return "Ok"; } }

이 코드는 다음과 같은 로그 출력을 생성합니다.

예 로그 형식
{ "timestamp": "2023-11-15T16:56:00.815Z", "level": "INFO", "message": "Handling s3 event", "logger": "example.HandlerS3", "AWSRequestId": "0bced576-3936-4e5a-9dcd-db9477b77f97", "awsRegion": "eu-south-1", "bucket": "java-logging-test-input-bucket", "eventName": "ObjectCreated:Put", "key": "test-folder/" }

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

예 build.gradle – 종속성 로깅
dependencies { ... 'com.amazonaws:aws-lambda-java-log4j2:[1.6.0,)', 'com.amazonaws:aws-lambda-java-events:[3.11.3,)', 'org.apache.logging.log4j:log4j-layout-template-json:[2.17.1,)', 'org.apache.logging.log4j:log4j-slf4j2-impl:[2.19.0,)', ... }

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

기타 도구 및 라이브러리

Powertools for AWS Lambda(Java)는 서버리스 모범 사례를 구현하고 개발자 속도를 높이기 위한 개발자 도구 키트입니다. Logging 유틸리티는 JSON으로 구조화된 출력과 함께 모든 함수의 함수 컨텍스트에 대한 추가 정보를 포함하는 Lambda 최적화 로거를 제공합니다. 이 유틸리티를 사용하여 다음을 수행합니다.

  • Lambda 컨텍스트, 콜드 스타트 및 구조 로깅 출력에서 JSON으로 주요 필드 캡처

  • 지시 시 Lambda 호출 이벤트 로깅(기본적으로 비활성화됨)

  • 로그 샘플링을 통해 호출 비율에 대해서만 모든 로그 인쇄(기본적으로 비활성화됨)

  • 언제든지 구조화된 로그에 추가 키 추가

  • 사용자 지정 로그 포맷터(Bring Your Own Formatter)를 사용하여 조직의 로깅 RFC와 호환되는 구조로 로그 출력

구조화된 로깅에 Powertools for AWS Lambda(Java) 및 AWS SAM 사용

다음 단계를 따라 AWS SAM을 사용하는 통합 Powertools for AWS Lambda(Java)~ 모듈을 사용하여 샘플 Hello World Java 애플리케이션을 다운로드, 빌드 및 배포합니다. 이 애플리케이션은 기본 API 백엔드를 구현하고 Powertools를 사용하여 로그, 지표 및 추적을 내보냅니다. 이 구성에는 Amazon API Gateway 엔드포인트와 Lambda 함수가 포함됩니다. API Gateway 엔드포인트로 GET 요청을 전송하면 Lambda 함수가 호출되고 Embedded Metric Format을 사용하여 로그 및 지표를 CloudWatch로 전송하고 기록을 AWS X-Ray로 전송합니다. 이 함수는 hello world 메시지를 반환합니다.

필수 조건

이 섹션의 단계를 완료하려면 다음이 필요합니다.

샘플 AWS SAM 애플리케이션 배포
  1. Hello World Java 템플릿을 사용하여 애플리케이션을 초기화합니다.

    sam init --app-template hello-world-powertools-java --name sam-app --package-type Zip --runtime java11 --no-tracing
  2. 앱을 빌드합니다.

    cd sam-app && sam build
  3. 앱을 배포합니다.

    sam deploy --guided
  4. 화면에 표시되는 프롬프트를 따릅니다. 대화형 환경에서 제공되는 기본 옵션을 수락하려면 Enter을 누릅니다.

    참고

    HelloWorldFunction에 권한 부여가 정의되어 있지 않을 수 있습니다. 괜찮습니다?에 대해 y를 입력합니다.

  5. 배포된 애플리케이션의 URL을 가져옵니다.

    aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
  6. API 엔드포인트 호출:

    curl -X GET <URL_FROM_PREVIOUS_STEP>

    성공하면 다음과 같은 결과가 응답됩니다.

    {"message":"hello world"}
  7. 함수에 대한 로그를 가져오려면 sam logs를 실행합니다. 자세한 내용은 AWS Serverless Application Model 개발자 안내서에서 로그 관련 작업을 참조하세요.

    sam logs --stack-name sam-app

    출력은 다음과 같습니다.

    2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:34.095000 INIT_START Runtime Version: java:11.v15 Runtime Version ARN: arn:aws:lambda:eu-central-1::runtime:0a25e3e7a1cc9ce404bc435eeb2ad358d8fa64338e618d0c224fe509403583ca 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:34.114000 Picked up JAVA_TOOL_OPTIONS: -XX:+TieredCompilation -XX:TieredStopAtLevel=1 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:34.793000 Transforming org/apache/logging/log4j/core/lookup/JndiLookup (lambdainternal.CustomerClassLoader@1a6c5a9e) 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:35.252000 START RequestId: 7fcf1548-d2d4-41cd-a9a8-6ae47c51f765 Version: $LATEST 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.531000 { "_aws": { "Timestamp": 1675416276051, "CloudWatchMetrics": [ { "Namespace": "sam-app-powerools-java", "Metrics": [ { "Name": "ColdStart", "Unit": "Count" } ], "Dimensions": [ [ "Service", "FunctionName" ] ] } ] }, "function_request_id": "7fcf1548-d2d4-41cd-a9a8-6ae47c51f765", "traceId": "Root=1-63dcd2d1-25f90b9d1c753a783547f4dd;Parent=e29684c1be352ce4;Sampled=1", "FunctionName": "sam-app-HelloWorldFunction-y9Iu1FLJJBGD", "functionVersion": "$LATEST", "ColdStart": 1.0, "Service": "service_undefined", "logStreamId": "2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81", "executionEnvironment": "AWS_Lambda_java11" } 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.974000 Feb 03, 2023 9:24:36 AM com.amazonaws.xray.AWSXRayRecorder <init> 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.993000 Feb 03, 2023 9:24:36 AM com.amazonaws.xray.config.DaemonConfiguration <init> 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.993000 INFO: Environment variable AWS_XRAY_DAEMON_ADDRESS is set. Emitting to daemon on address XXXX.XXXX.XXXX.XXXX:2000. 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:37.331000 09:24:37.294 [main] INFO helloworld.App - {"version":null,"resource":"/hello","path":"/hello/","httpMethod":"GET","headers":{"Accept":"*/*","CloudFront-Forwarded-Proto":"https","CloudFront-Is-Desktop-Viewer":"true","CloudFront-Is-Mobile-Viewer":"false","CloudFront-Is-SmartTV-Viewer":"false","CloudFront-Is-Tablet-Viewer":"false","CloudFront-Viewer-ASN":"16509","CloudFront-Viewer-Country":"IE","Host":"XXXX.execute-api.eu-central-1.amazonaws.com","User-Agent":"curl/7.86.0","Via":"2.0 f0300a9921a99446a44423d996042050.cloudfront.net (CloudFront)","X-Amz-Cf-Id":"t9W5ByT11HaY33NM8YioKECn_4eMpNsOMPfEVRczD7T1RdhbtiwV1Q==","X-Amzn-Trace-Id":"Root=1-63dcd2d1-25f90b9d1c753a783547f4dd","X-Forwarded-For":"XX.XXX.XXX.XX, XX.XXX.XXX.XX","X-Forwarded-Port":"443","X-Forwarded-Proto":"https"},"multiValueHeaders":{"Accept":["*/*"],"CloudFront-Forwarded-Proto":["https"],"CloudFront-Is-Desktop-Viewer":["true"],"CloudFront-Is-Mobile-Viewer":["false"],"CloudFront-Is-SmartTV-Viewer":["false"],"CloudFront-Is-Tablet-Viewer":["false"],"CloudFront-Viewer-ASN":["16509"],"CloudFront-Viewer-Country":["IE"],"Host":["XXXX.execute-api.eu-central-1.amazonaws.com"],"User-Agent":["curl/7.86.0"],"Via":["2.0 f0300a9921a99446a44423d996042050.cloudfront.net (CloudFront)"],"X-Amz-Cf-Id":["t9W5ByT11HaY33NM8YioKECn_4eMpNsOMPfEVRczD7T1RdhbtiwV1Q=="],"X-Amzn-Trace-Id":["Root=1-63dcd2d1-25f90b9d1c753a783547f4dd"],"X-Forwarded-For":["XXX, XXX"],"X-Forwarded-Port":["443"],"X-Forwarded-Proto":["https"]},"queryStringParameters":null,"multiValueQueryStringParameters":null,"pathParameters":null,"stageVariables":null,"requestContext":{"accountId":"XXX","stage":"Prod","resourceId":"at73a1","requestId":"ba09ecd2-acf3-40f6-89af-fad32df67597","operationName":null,"identity":{"cognitoIdentityPoolId":null,"accountId":null,"cognitoIdentityId":null,"caller":null,"apiKey":null,"principalOrgId":null,"sourceIp":"54.240.197.236","cognitoAuthenticationType":null,"cognitoAuthenticationProvider":null,"userArn":null,"userAgent":"curl/7.86.0","user":null,"accessKey":null},"resourcePath":"/hello","httpMethod":"GET","apiId":"XXX","path":"/Prod/hello/","authorizer":null},"body":null,"isBase64Encoded":false} 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:37.351000 09:24:37.351 [main] INFO helloworld.App - Retrieving https://checkip.amazonaws.com 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:39.313000 { "function_request_id": "7fcf1548-d2d4-41cd-a9a8-6ae47c51f765", "traceId": "Root=1-63dcd2d1-25f90b9d1c753a783547f4dd;Parent=e29684c1be352ce4;Sampled=1", "xray_trace_id": "1-63dcd2d1-25f90b9d1c753a783547f4dd", "functionVersion": "$LATEST", "Service": "service_undefined", "logStreamId": "2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81", "executionEnvironment": "AWS_Lambda_java11" } 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:39.371000 END RequestId: 7fcf1548-d2d4-41cd-a9a8-6ae47c51f765 2023/02/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:39.371000 REPORT RequestId: 7fcf1548-d2d4-41cd-a9a8-6ae47c51f765 Duration: 4118.98 ms Billed Duration: 4119 ms Memory Size: 512 MB Max Memory Used: 152 MB Init Duration: 1155.47 ms XRAY TraceId: 1-63dcd2d1-25f90b9d1c753a783547f4dd SegmentId: 3a028fee19b895cb Sampled: true
  8. 이는 인터넷을 통해 액세스할 수 있는 퍼블릭 API 엔드포인트입니다. 테스트 후에는 엔드포인트를 삭제하는 것이 좋습니다.

    sam delete

로그 보존 관리

함수를 삭제해도 로그 그룹이 자동으로 삭제되지 않습니다. 로그를 무기한 저장하지 않으려면 로그 그룹을 삭제하거나 경과 후 CloudWatch가 로그를 자동으로 삭제하는 보존 기간을 구성하세요. 로그 보존을 설정하려면 AWS SAM 템플릿에 다음을 추가합니다.

Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: # Omitting other properties LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/aws/lambda/${HelloWorldFunction}" RetentionInDays: 7

Lambda 콘솔 사용

Lambda 함수를 호출한 후 Lambda 콘솔을 사용하여 로그 출력을 볼 수 있습니다.

포함된 코드 편집기에서 코드를 테스트할 수 있는 경우 실행 결과에서 로그를 찾을 수 있습니다. 콘솔 테스트 기능을 사용하여 함수를 간접적으로 호출하면 세부 정보 섹션에서 로그 출력을 찾을 수 있습니다.

CloudWatch 콘솔 사용

Amazon CloudWatch 콘솔을 사용하여 모든 Lambda 함수 호출에 대한 로그를 볼 수 있습니다.

CloudWatch 콘솔에서 로그를 보려면
  1. CloudWatch 콘솔에서 로그 그룹 페이지를 엽니다.

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

  3. 로그 스트림을 선택합니다.

각 로그 스트림은 함수의 인스턴스에 해당합니다. 로그 스트림은 Lambda 함수를 업데이트할 때, 그리고 여러 동시 호출을 처리하기 위해 추가 인스턴스가 생성될 때 나타납니다. 특정 호출에 대한 로그를 찾으려면 AWS X-Ray로 함수를 계측하는 것이 좋습니다. X-Ray는 요청 및 로그 스트림에 대한 세부 정보를 기록합니다.

로그 및 추적을 X-Ray와 상호 연관시키는 샘플 애플리케이션을 사용하려면 AWS Lambda용 오류 처리자 샘플 애플리케이션 단원을 참조하세요.

AWS Command Line Interface(AWS CLI) 사용

AWS CLI은(는) 명령줄 셸의 명령을 사용하여 AWS 서비스와 상호 작용할 수 있는 오픈 소스 도구입니다. 이 섹션의 단계를 완료하려면 다음이 필요합니다.

AWS CLI를 사용하면 --log-type 명령 옵션을 통해 호출에 대한 로그를 검색할 수 있습니다. 호출에서 base64로 인코딩된 로그를 최대 4KB까지 포함하는 LogResult 필드가 응답에 포함됩니다.

예 로그 ID 검색

다음 예제에서는 LogResult이라는 함수의 my-function 필드에서 로그 ID를 검색하는 방법을 보여줍니다.

aws lambda invoke --function-name my-function out --log-type Tail

다음 결과가 표시됩니다:

{ "StatusCode": 200, "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...", "ExecutedVersion": "$LATEST" }
예 decode the logs

동일한 명령 프롬프트에서 base64 유틸리티를 사용하여 로그를 디코딩합니다. 다음 예제에서는 my-function에 대한 base64로 인코딩된 로그를 검색하는 방법을 보여줍니다.

aws lambda invoke --function-name my-function out --log-type Tail \ --query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode

cli-binary-format 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 aws configure set cli-binary-format raw-in-base64-out을(를) 실행하세요. 자세한 내용은 AWS CLI 지원되는 글로벌 명령줄 옵션을 AWS Command Line Interface 사용 설명서 버전 2에서 참조하세요.

다음 결과가 표시됩니다.

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: 80 ms Memory Size: 128 MB Max Memory Used: 73 MB

base64 유틸리티는 Linux, macOS 및 Ubuntu on Windows에서 사용할 수 있습니다. macOS 사용자는 base64 -D를 사용해야 할 수도 있습니다.

예 get-logs.sh 스크립트

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

다음 코드 샘플의 내용을 복사하고 Lambda 프로젝트 디렉터리에 get-logs.sh로 저장합니다.

cli-binary-format 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 aws configure set cli-binary-format raw-in-base64-out을(를) 실행하세요. 자세한 내용은 AWS CLI 지원되는 글로벌 명령줄 옵션을 AWS Command Line Interface 사용 설명서 버전 2에서 참조하세요.

#!/bin/bash aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --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 stream1 --limit 5
예 macOS 및 Linux(전용)

동일한 명령 프롬프트에서 macOS 및 Linux 사용자는 스크립트가 실행 가능한지 확인하기 위해 다음 명령을 실행해야 할 수 있습니다.

chmod -R 755 get-logs.sh
예 마지막 5개 로그 이벤트 검색

동일한 명령 프롬프트에서 다음 스크립트를 실행하여 마지막 5개 로그 이벤트를 가져옵니다.

./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: 27 ms \tMemory Size: 128 MB\tMax Memory Used: 75 MB\t\n", "ingestionTime": 1559763018353 } ], "nextForwardToken": "f/34783877304859518393868359594929986069206639495374241795", "nextBackwardToken": "b/34783877303811383369537420289090800615709599058929582080" }

로그 삭제

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

샘플 로깅 코드

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

Java의 샘플 Lambda 애플리케이션
  • java17-examples – Java 레코드를 사용하여 입력 이벤트 데이터 객체를 나타내는 방법을 보여주는 Java 함수입니다.

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

  • java - Amazon API Gateway, Amazon SQS 및 Amazon Kinesis와 같은 다양한 서비스의 이벤트를 처리하는 방법에 대한 스켈레톤 코드가 포함된 Java 함수 모음입니다. 이러한 함수는 최신 버전의 aws-lambda-java-events 라이브러리(3.0.0 이상)를 사용합니다. 이러한 예는 AWS SDK를 종속 항목으로 요구하지 않습니다.

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

  • API Gateway를 사용하여 Lambda 함수 호출 — 직원 정보가 포함된 Amazon DynamoDB 테이블을 스캔하는 Java 함수입니다. 이후 Amazon 간편 알림 서비스를 사용하여 직원들에게 근무 기념일을 축하하는 문자 메시지를 보냅니다. 이 예제에서는 API Gateway를 사용하여 함수를 호출합니다.

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