CloudWatch Log Group 로그를 S3로 Automatically하게 이전하기
2021-2022 기간동안 스타트업에서 데브옵스 엔지니어로 일할 때 개인 노션에 트러블슈팅을 기록했던 내용을 블로그로 옮깁니다.
AS IS
- CloudWatch의 Log Group에 로그가 쌓이고 있음
- 비쌈
TO BE
- Exporter를 통해 CW Log Group이 아닌 S3로 로그를 저장하기
TRIED
내가 하려고 했던 작업을 분명 해본 사람이 있을거라 생각하고 찾아보니, 미디엄에 정확히 같은 내용의 글이 있었다.
Exporting Cloudwatch Logs automatically to S3 With a Lambda function
그래서 그대로 시도를 해봤는데 아래와 같은 에러가 출력됐다.
2022-06-09T00:44:50.137+09:00
[ERROR] ClientError: An error occurred (ThrottlingException) when calling the ListTagsLogGroup operation (reached max retries: 4): Rate exceeded
Traceback (most recent call last):
File "/var/task/cloudwatch-to-s3.py", line 29, in lambda_handler
response = logs.list_tags_log_group(logGroupName=log_group['logGroupName'])
File "/var/runtime/botocore/client.py", line 391, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/var/runtime/botocore/client.py", line 719, in _make_api_call
raise error_class(parsed_response, operation_name)
[ERROR] ClientError: An error occurred (ThrottlingException) when calling the ListTagsLogGroup operation (reached max retries: 4): Rate exceeded Traceback (most recent call last): File "/var/task/cloudwatch-to-s3.py", line 29, in lambda_handler response = logs.list_tags_log_group(logGroupName=log_group['logGroupName']) File "/var/runtime/botocore/client.py", line 391, in _api_call return self._make_api_call(operation_name, kwargs) File "/var/runtime/botocore/client.py", line 719, in _make_api_call raise error_class(parsed_response, operation_name)
오류 내용을 요약해보면, 짧은 시간에 AWS에 너무 많은 요청을 보냈다는 뜻인 것 같은데, 이는 Export 작업을 수행하는 Lambda 코드에서 발생한 것으로 보였다. (람다 관련 클라우드워치 로그였기 때문)
Trouble Shooting v1
Exporting Cloudwatch Logs automatically to S3 With a Lambda function
위 링크에서 올려놓은 코드를 분석해보았는데, 아래 부분에서 문제의 해답을 찾을 수 있었다. 비효율적으로 동작하고 있는 것으로 보였는데, 이 부분에서 AWS에 너무 많은 요청을 보내게 되면서 오류가 발생한 것 같았다. (해당 코드가 CW log-group 리소스가 적을 때는 문제가 없었겠지만, 회사처럼 리소스가 많은 곳에서는 모든 log-group에 대한 정보를 API에 매번 요청하면서 요청 횟수 초과가 발생한 듯하다.)
- 첫 번째 근거로
boto3
AWS 라이브러리를 쓰고 있는 부분 - 두 번째 근거로 순회를 돌면서 AWS API 요청을 보내고 있었기 때문
for log_group in log_groups:
response = logs.list_tags_log_group(logGroupName=log_group['logGroupName'])
log_group_tags = response['tags']
if 'ExportToS3' in log_group_tags and log_group_tags['ExportToS3'] == 'true':
log_groups_to_export.append(log_group['logGroupName'])
위에서 사용하는 log_groups 자체를 내가 export하고자하는 log_group으로 특정지어주면 되는 문제였다.
while True:
# 기존 코드
# response = logs.describe_log_groups(**extra_args)
# 수정한 코드
response = logs.describe_log_groups(logGroupNamePrefix="로그그룹명")
log_groups = log_groups + response['logGroups']
Trouble Shooting v2
새로운 오류가 생겼다!
Error exporting 로그그룹명:
InvalidParameterException('An error occurred (InvalidParameterException)
when calling the CreateExportTask operation: GetBucketAcl call on the given bucket failed.
Please check if CloudWatch Logs has been granted permission to perform this operation.')
또 열심히 검색을 해서 레퍼런스를 찾았다. Amazon S3로 Log Data 내보내는 방법. (Bucket Policy)
- bucket에 관련한 policy가 없어서 그런게 아닐까 추측했다. GetBucketAcl에 대한 설정 문제인 것으로 보였기 때문이다.
- 따라서 aws_s3_bucket_policy 를 작성했다. 가장 중요한 포인트는 다음과 같다.
{
"Sid": "CWLogsAcl",
"Effect": "Allow",
"Principal": {
"Service": "logs.amazonaws.com"
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::${aws_s3_bucket.로그그룹명.bucket}"
}
SOLVED
해결했다!