Lambda 함수의 CloudWatch 로그 보기
Lambda 함수의 CloudWatch 로그 보기 (Viewing CloudWatch logs for Lambda functions)
Lambda 함수의 Amazon CloudWatch 로그는 Lambda 콘솔, CloudWatch 콘솔, 또는 AWS Command Line Interface(AWS CLI)로 볼 수 있어요. 다음 섹션의 지침에 따라 함수의 로그에 접근하세요.
본문
CloudWatch Logs Live Tail로 함수 로그 스트리밍
Amazon CloudWatch Logs Live Tail은 Lambda 콘솔에서 새 로그 이벤트의 스트리밍 목록을 실시간으로 보여줘 함수를 빠르게 문제 해결하는 데 도움을 줘요. Lambda 함수에서 수집된 로그를 실시간으로 보고 필터링해 문제를 빠르게 감지·해결할 수 있어요.
참고
Live Tail 세션은 세션 사용 시간(분당)에 따라 비용이 부과돼요.
Live Tail과 --log-type Tail 비교
CloudWatch Logs Live Tail과 Lambda API의 LogType: Tail 옵션(AWS CLI의 --log-type Tail) 사이에는 여러 차이가 있어요.
--log-type Tail은 호출 로그의 처음 4KB만 반환합니다. Live Tail은 이 제한이 없고 초당 최대 500개의 로그 이벤트를 받을 수 있습니다.--log-type Tail은 응답과 함께 로그를 캡처·전송해 함수의 응답 지연에 영향을 줄 수 있습니다. Live Tail은 함수 응답 지연에 영향을 주지 않습니다.--log-type Tail은 동기 호출만 지원합니다. Live Tail은 동기·비동기 호출 모두에서 작동합니다.
참고
Lambda Managed Instances는
--log-type Tail옵션을 지원하지 않아요. Managed Instances 함수의 로그를 보려면 CloudWatch Logs Live Tail을 사용하거나 CloudWatch Logs를 직접 쿼리하세요.
권한
CloudWatch Logs Live Tail 세션을 시작·중지하려면 다음 권한이 필요해요.
- logs:DescribeLogGroups
- logs:StartLiveTail
- logs:StopLiveTail
Lambda 콘솔에서 Live Tail 세션 시작
- Lambda 콘솔의 Functions 페이지를 엽니다.
- 함수의 이름을 선택합니다.
- Test 탭을 선택합니다.
- Test event 창에서 CloudWatch Logs Live Tail을 선택합니다.
- Select log groups에서 함수의 로그 그룹이 기본으로 선택됩니다. 한 번에 최대 5개의 로그 그룹을 선택할 수 있습니다.
- (선택 사항) 특정 단어나 문자열을 포함한 로그 이벤트만 표시하려면 Add filter pattern 상자에 단어나 문자열을 입력합니다. 필터 필드는 대소문자를 구분합니다. 정규 표현식(regex)을 포함한 여러 용어와 패턴 연산자를 입력할 수 있습니다.
- Start를 선택합니다. 일치하는 로그 이벤트가 창에 나타나기 시작합니다.
- Live Tail 세션을 중지하려면 Stop을 선택합니다.
참고
Live Tail 세션은 15분의 비활성 후 또는 Lambda 콘솔 세션이 타임아웃되면 자동으로 중지돼요.
콘솔로 함수 로그 접근
- Lambda 콘솔의 Functions 페이지를 엽니다.
- 함수를 선택합니다.
- Monitor 탭을 선택합니다.
- View CloudWatch logs를 선택해 CloudWatch 콘솔을 엽니다.
- 스크롤해 보려는 함수 호출의 Log stream을 선택합니다.
Lambda 함수의 각 인스턴스는 전용 로그 스트림이 있어요. 함수가 확장되면 각 동시 인스턴스마다 자체 로그 스트림이 있어요. 호출에 응답해 새 실행 환경이 생성될 때마다 새 로그 스트림이 생성돼요. 로그 스트림의 명명 규칙은 다음과 같아요.
YYYY/MM/DD[Function version][Execution environment GUID]
단일 실행 환경은 수명 동안 같은 로그 스트림에 써요. 로그 스트림에는 그 실행 환경의 메시지와 Lambda 함수 코드의 출력이 포함돼요. 커스텀 로그를 포함한 모든 메시지에 타임스탬프가 찍혀요. 함수가 코드에서 어떤 출력도 기록하지 않더라도 호출마다 세 개의 최소 로그 문(START, END, REPORT)이 생성돼요. 이 로그는 다음을 보여줘요.
- RequestId – 요청마다 생성되는 고유 ID입니다. Lambda 함수가 요청을 재시도하면 이 ID는 바뀌지 않고 이후 각 재시도의 로그에 나타납니다.
- Start/End – 단일 호출을 마킹하므로, 그 사이의 모든 로그 줄은 같은 호출에 속합니다.
- Duration – INIT 코드를 제외한 핸들러 함수의 총 호출 시간입니다.
- Billed Duration – 청구를 위한 반올림 로직을 적용합니다.
- Memory Size – 함수에 할당된 메모리 양입니다.
- Max Memory Used – 호출 중 사용된 최대 메모리 양입니다.
- Init Duration – 메인 핸들러 밖의 INIT 코드 섹션을 실행하는 데 걸린 시간입니다.
AWS CLI로 로그 접근
AWS CLI는 명령줄 셸의 명령으로 AWS 서비스와 상호작용할 수 있는 오픈소스 도구예요. 이 섹션의 단계를 완료하려면 AWS CLI 버전 2가 있어야 해요.
AWS CLI로 --log-type 명령 옵션을 사용해 호출의 로그를 검색할 수 있어요. 응답에는 호출에서 최대 4KB의 base64로 인코딩된 로그가 담긴 LogResult 필드가 포함돼요.
예제 — 로그 ID 검색
aws lambda invoke --function-name my-function out --log-type Tail
다음과 같은 출력이 보여야 해요.
{
"StatusCode": 200,
"LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...",
"ExecutedVersion": "$LATEST"
}
예제 — 로그 디코딩
aws lambda invoke --function-name my-function out --log-type Tail \
--query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode
다음과 같은 출력이 보여야 해요.
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초 동안 sleep해요. 이 코드 샘플을 복사해 Lambda 프로젝트 디렉토리에 get-logs.sh로 저장하세요.
#!/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(전용)
chmod -R 755 get-logs.sh
예제 — 마지막 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"
}
로그 파싱과 구조화된 로깅
CloudWatch Logs Insights로 특수한 쿼리 구문을 사용해 로그 데이터를 검색·분석할 수 있어요. 여러 로그 그룹에 걸쳐 쿼리를 수행하고 glob과 정규 표현식 패턴 매칭으로 강력한 필터링을 제공해요.
Lambda 함수에서 구조화된 로깅(structured logging)을 구현하면 이 기능을 활용할 수 있어요. 구조화된 로깅은 로그를 사전 정의된 형식으로 구성해 쿼리하기 쉽게 만들어요. 로그 레벨을 사용하는 것은 정보 메시지를 경고·오류와 구분하는 필터 친화적인 로그를 만드는 중요한 첫 단계예요. 예를 들어 다음 Node.js 코드를 고려해요.
exports.handler = async (event) => {
console.log("console.log - Application is fine")
console.info("console.info - This is the same as console.log")
console.warn("console.warn - Application provides a warning")
console.error("console.error - An error occurred")
}
결과 CloudWatch 로그 파일에는 로그 레벨을 지정하는 별도 필드가 포함돼요. CloudWatch Logs Insights 쿼리는 로그 레벨로 필터링할 수 있어요. 예를 들어 오류만 쿼리하려면 다음 쿼리를 사용해요.
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
JSON 구조화된 로깅
JSON은 애플리케이션 로그에 구조를 제공하는 데 흔히 사용돼요. 다음 예시에서 로그는 세 개의 별도 값을 출력하도록 JSON으로 변환됐어요. CloudWatch Logs Insights는 JSON 출력의 값을 자동으로 발견하고 커스텀 glob이나 정규 표현식 없이 메시지를 필드로 파싱해요. JSON 구조화 로그를 사용해 다음 쿼리는 업로드된 파일이 1MB보다 크고, 업로드 시간이 1초보다 길고, 호출이 콜드 스타트가 아닌 호출을 찾아요.
fields @message
| filter @message like /INFO/
| filter uploadedBytes > 1000000
| filter uploadTimeMS > 1000
| filter invocation != 1
JSON에서 발견된 필드는 오른쪽의 Discovered fields 메뉴에 자동으로 채워져요. Lambda 서비스가 내보내는 표준 필드에는 @가 붙으며 같은 방식으로 쿼리할 수 있어요. Lambda 로그에는 항상 @timestamp, @logStream, @message, @requestId, @duration, @billedDuration, @type, @maxMemoryUsed, @memorySize 필드가 포함돼요. 함수에 X-Ray가 활성화되어 있으면 로그에 @xrayTraceId와 @xraySegmentId도 포함돼요.
Amazon S3, Amazon SQS, Amazon EventBridge 같은 AWS 이벤트 소스가 함수를 호출하면 전체 이벤트가 JSON 객체 입력으로 함수에 제공돼요. 함수의 첫 줄에서 이 이벤트를 로깅하면 CloudWatch Logs Insights로 중첩 필드 중 어떤 것이든 쿼리할 수 있어요.
유용한 Insights 쿼리
다음 표는 Lambda 함수 모니터링에 유용한 예시 Insights 쿼리를 보여줘요.
| 설명 | 예시 쿼리 구문 |
|---|---|
| 마지막 100개 오류 | fields Timestamp, LogLevel, Message | filter LogLevel == "ERR" | sort @timestamp desc | limit 100 |
| 청구액 상위 100개 호출 | filter @type = "REPORT" | fields @requestId, @billedDuration | sort by @billedDuration desc | limit 100 |
| 총 호출 중 콜드 스타트 비율 | filter @type = "REPORT" | stats sum(strcontains(@message, "Init Duration"))/count(*) * 100 as coldStartPct, avg(@duration) by bin(5m) |
| Lambda duration 백분위수 보고서 | filter @type = "REPORT" | stats avg(@billedDuration) as Average, percentile(@billedDuration, 99) as NinetyNinth, percentile(@billedDuration, 95) as NinetyFifth, percentile(@billedDuration, 90) as Ninetieth by bin(30m) |
| Lambda 메모리 사용 백분위수 보고서 | filter @type="REPORT" | stats avg(@maxMemoryUsed/1024/1024) as mean_MemoryUsed, min(@maxMemoryUsed/1024/1024) as min_MemoryUsed, max(@maxMemoryUsed/1024/1024) as max_MemoryUsed, percentile(@maxMemoryUsed/1024/1024, 95) as Percentile95 |
| 할당된 메모리의 100%를 사용한 호출 | filter @type = "REPORT" and @maxMemoryUsed=@memorySize | stats count_distinct(@requestId) by bin(30m) |
| 호출 전체의 평균 메모리 사용 | avgMemoryUsedPERC, avg(@billedDuration) as avgDurationMS by bin(5m) |
| 메모리 통계 시각화 | filter @type = "REPORT" | stats max(@maxMemoryUsed / 1024 / 1024) as maxMemMB, avg(@maxMemoryUsed / 1024 / 1024) as avgMemMB, min(@maxMemoryUsed / 1024 / 1024) as minMemMB, (avg(@maxMemoryUsed / 1024 / 1024) / max(@memorySize / 1024 / 1024)) * 100 as avgMemUsedPct, avg(@billedDuration) as avgDurationMS by bin(30m) |
| Lambda가 종료된 호출 | filter @message like /Process exited/ | stats count() by bin(30m) |
| 타임아웃된 호출 | filter @message like /Task timed out/ | stats count() by bin(30m) |
| 지연 보고서 | filter @type = "REPORT" | stats avg(@duration), max(@duration), min(@duration) by bin(5m) |
| 초과 프로비저닝된 메모리 | filter @type = "REPORT" | stats max(@memorySize / 1024 / 1024) as provisonedMemMB, min(@maxMemoryUsed / 1024 / 1024) as smallestMemReqMB, avg(@maxMemoryUsed / 1024 / 1024) as avgMemUsedMB, max(@maxMemoryUsed / 1024 / 1024) as maxMemUsedMB, provisonedMemMB - maxMemUsedMB as overProvisionedMB |
로그 시각화와 대시보드
어떤 CloudWatch Logs Insights 쿼리든 결과를 markdown이나 CSV 형식으로 내보낼 수 있어요. 어떤 경우에는 최소 하나의 집계 함수가 있다면 쿼리에서 시각화를 만드는 것이 더 유용할 수 있어요. stats 함수로 집계와 그룹화를 정의할 수 있어요.
위 logInsightsJSON 예시는 업로드 크기와 업로드 시간으로 필터링하고 첫 호출을 제외했어요. 이 결과는 데이터 표가 됐어요. 프로덕션 시스템을 모니터링할 때 이상값을 찾기 위해 최소·최대·평균 파일 크기를 시각화하는 것이 더 유용할 수 있어요. 이렇게 하려면 필요한 집계와 함께 stats 함수를 적용하고 매분 같은 시간 값으로 그룹화하세요.
예를 들어 다음 쿼리를 고려해요. JSON 구조화된 로깅 섹션의 예시 쿼리와 같지만 추가 집계 함수가 있어요.
fields @message
| filter @message like /INFO/
| filter uploadedBytes > 1000000
| filter uploadTimeMS > 1000
| filter invocation != 1
| stats min(uploadedBytes), avg(uploadedBytes), max(uploadedBytes) by bin (1m)
이 집계를 포함한 이유는 이상값을 찾기 위해 최소·최대·평균 파일 크기를 시각화하는 것이 더 유용할 수 있기 때문이에요. Visualization 탭에서 결과를 볼 수 있어요. 시각화 구축을 마친 후 선택적으로 그래프를 CloudWatch 대시보드에 추가할 수 있어요. 시각화 위의 Add to dashboard를 선택하세요. 이렇게 하면 쿼리가 위젯으로 추가되고 자동 새로고침 간격을 선택해 결과를 지속적으로 모니터링하기 쉬워져요.