4
3

More than 5 years have passed since last update.

CloudWatch LogsにあるログをLambdaを使用してS3に転送する

Last updated at Posted at 2019-08-10

このページはなに

表題通りとなりますが、Lambda関数を使用してCloudWatch LogsにあるログをS3に転送する仕組みを実装します。

参考にさせていただいたURL

背景

AWSサービスの中でファイルの配置の料金が一番安いのはS3です。
なので、例えばCloudWatch Logsに格納しているログについては7日保管にして、S3には1年間保管のような仕組みをつくりたいと考えました。

仕組み(構成図)

構成図.png

作業手順

IAMロール(ポリシー)の作成

以下、IAMポリシーを作成してIAMロールにアタッチしてLambdaに紐づけてください。
(LambdaがS3バケットへの操作の権限が必要なため)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"     # S3バケット内のリスト表示に必要(最初に接続確認をするため)
            ],
            "Resource": "arn:aws:s3:::S3バケット名"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",     # S3バケットにログを配置する前にS3バケット内のファイルの存在を確認するための権限
                "s3:PutObject"     # S3バケットにログを配置するための権限
            ],
            "Resource": "arn:aws:s3:::S3バケット名/*"
        }
    ]
}

S3バケットポリシーの設定

・吐き出す先のS3バケットポリシーに、以下のバケットポリシーを設定してください。
・補足:この設定は、CloudWatch LogsからS3バケットにログを配置するために必要なバケットポリシーになります。
 (CloudWatch LogsにIAMロールは紐づけられないので、S3のバケットポリシーで制御します。)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.対象リージョン.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",     # CloudWatch Logsから S3バケットのアクセス(s3apiコール)制御のポリシー 
            "Resource": "arn:aws:s3:::S3バケット名"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.対象リージョン.amazonaws.com"
            },
            "Action": "s3:PutObject",     # CloudWatch Logsから S3バケットへログ配置するためのS3バケットポリシー 
            "Resource": "arn:aws:s3:::S3バケット名/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }
    ]
}

Lambda関数の作成

・使用言語は、python3。バージョンは、3.7です。

コード

コードは「参考にさせていただいたサイト」に記載してある内容とほぼ同じです。
コード内に記載されているコメントアウト部分を、環境ごとに適宜編集していく形になります。

import datetime
import time
import boto3

log_group_name = 'ロググループ名'    #CloudWatchLogsのロググループ名
s3_bucket_name = 'S3バケット名'    #保存先S3バケット名
s3_string_prefix = 'S3内のプレフィックス'    #S3内のプレフィックス(文字列)を定義
s3_date_prefix = '/%s' % (datetime.date.today() - datetime.timedelta(days = 1))    #S3内のプレフィックス(日付)を定義

def get_from_timestamp():
    today = datetime.date.today()
    yesterday = datetime.datetime.combine(today - datetime.timedelta(days = 1), datetime.time(0, 0, 0))
    timestamp = time.mktime(yesterday.timetuple())
    return int(timestamp)

def get_to_timestamp(from_ts):
    return from_ts + (60 * 60 * 24) - 1

def lambda_handler(event, context):
    from_ts = get_from_timestamp()
    to_ts = get_to_timestamp(from_ts)
    print('Timestamp: from_ts %s, to_ts %s' % (from_ts, to_ts))

    client = boto3.client('logs')
    response = client.create_export_task(
        logGroupName      = log_group_name,     #取得するCloudWatchロググループ名
        fromTime          = from_ts * 1000,
        to                = to_ts * 1000,
        destination       = s3_bucket_name,     #保存先S3バケット名
        destinationPrefix = s3_string_prefix + s3_date_prefix   #保存先S3バケット名配下の任意のサブフォルダ名(プレフィックス名)
    )
    return response

CloudWatch Eventの作成

毎日AM4:00にイベント発生する場合、CloudWatch Eventに以下のcron設定をすればおkです。
(時間がUTC形式のため、UTCから+9時間することを忘れずに。)

0 19 * * ? *

悩んだこと

S3に吐き出したときのファイル名が「000000.gz」になってしまうので、ファイル名を変える方法を調べましたが、boto3のapiの仕様で「000000」で吐き出されてしまうようです(ファイル名を別ネームで保存したい場合は、別途仕組みを実装する必要あり)。

boto3_URL

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3