본문으로 바로가기
반응형

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에 접근을 해서 해당 경로로 파일이 잘 생성되는지 확인해 보았습니다. 문제없이 잘들어 옵니다.

반응형