Intro
Cloudfront는 AWS의 CDN서비스 입니다. CDN서비스는 고객이 접근하는 최상단에 위치하며 주로 정적이미지를 캐싱하는 역할을 담당합니다. 이 Cloudfront의 Log기능을 활성화하면 아래와 같이 S3에 Access log를 저장할 수 있습니다.

이 로그를 날짜별 폴더 구조로 관리하고 싶을때 어떻게 해야할까요?
Cloudfront Log 저장 경로
기본적으로 cloudfront의 Log기능을 활성화하면 S3버킷명과 prefix정보를 입력하게 됩니다. 예를들어 s3버킷명이 test
이고 prefix가 aws/cloudfront
라고하면 test/aws/cloudfront/cloudfront_access_log.gz
형태로 로그가 저장이 됩니다.
날짜 경로로 저장하기
cloudfront Log가 S3에 저장될때 아래와같이 날짜 경로로 저장 되도록 하려면 Lambda 함수를 만들어서 S3 트리거를 걸어 줘야합니다.
├── bucket_name
│ ├── 2021
│ │ ├── 10
│ │ │ ├── 14
│ │ │ │ ├── 08
오늘 제가 하고자 하는 비슷한 예제는 AWS에서 확인할 수 있습니다.

https://aws.amazon.com/ko/blogs/big-data/analyze-your-amazon-cloudfront-access-logs-at-scale/
AWS 샘플 코드 (nodejs)
위 그림과 같이 람다함수를 통해 날짜 폴더에 copy를 하고 기존 데이터는 delete 하는 샘플 코드는 다음 URL에서 확인이 가능합니다.
https://github.com/aws-samples/amazon-cloudfront-access-logs-queries/blob/mainline/functions/moveAccessLogs.js
날짜 경로 저장하는 소스코드 (nodejs)
위의 AWS 샘플코드를 조금 변형하여 날짜 경로로 저장하는 소스코드를 만들어 보았습니다.const targetKeyPrefix = process.env.TARGET_KEY_PREFIX;
const targetKey = "${targetKeyPrefix}year=${year}/month=${month}/day=${day}/hour=${hour}/${filename}";
부분을 수정하였으며 targetKeyPrefix는 하드코딩하였으니 수정하여 사용하시면 됩니다.
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. | |
// SPDX-License-Identifier: MIT-0 | |
const aws = require('aws-sdk'); | |
const s3 = new aws.S3({ apiVersion: '2006-03-01' }); | |
// prefix to copy partitioned data to w/o leading but w/ trailing slash | |
// const targetKeyPrefix = process.env.TARGET_KEY_PREFIX; | |
const targetKeyPrefix = "aws/cloudfront" | |
// regex for filenames by Amazon CloudFront access logs. Groups: | |
// - 1. year | |
// - 2. month | |
// - 3. day | |
// - 4. hour | |
const datePattern = '[^\\d](\\d{4})-(\\d{2})-(\\d{2})-(\\d{2})[^\\d]'; | |
const filenamePattern = '[^/]+$'; | |
exports.handler = async (event, context, callback) => { | |
const moves = event.Records.map(record => { | |
const bucket = record.s3.bucket.name; | |
const sourceKey = record.s3.object.key; | |
const sourceRegex = new RegExp(datePattern, 'g'); | |
const match = sourceRegex.exec(sourceKey); | |
if (match == null) { | |
console.log(`Object key ${sourceKey} does not look like an access log file, so it will not be moved.`); | |
} else { | |
const [, year, month, day, hour] = match; | |
const filenameRegex = new RegExp(filenamePattern, 'g'); | |
const filename = filenameRegex.exec(sourceKey)[0]; | |
const targetKey = `${targetKeyPrefix}/${year}/${month}/${day}/${hour}/${filename}`; | |
console.log(`Copying ${sourceKey} to ${targetKey}.`); | |
const copyParams = { | |
CopySource: bucket + '/' + sourceKey, | |
Bucket: bucket, | |
Key: targetKey | |
}; | |
const copy = s3.copyObject(copyParams).promise(); | |
const deleteParams = { Bucket: bucket, Key: sourceKey }; | |
return copy.then(function () { | |
console.log(`Copied. Now deleting ${sourceKey}.`); | |
const del = s3.deleteObject(deleteParams).promise(); | |
console.log(`Deleted ${sourceKey}.`); | |
return del; | |
}, function (reason) { | |
var error = new Error(`Error while copying ${sourceKey}: ${reason}`); | |
callback(error); | |
}); | |
} | |
}); | |
await Promise.all(moves); | |
}; |
AWS람다 함수 생성 및 트리거 설정
AWS 람다 함수를 만들면 아래 그림과같이 트리거를 추가할 수 있습니다.



검토
실제 Cloudfront에 접근을 해서 해당 경로로 파일이 잘 생성되는지 확인해 보았습니다. 문제없이 잘들어 옵니다.
