LoginSignup
46
41

More than 3 years have passed since last update.

CloudWatchLogsをLambdaで自動的にS3へアップロードする1つの仕掛け

Last updated at Posted at 2019-02-26

あなたはCloudWatchで収集したログを放置していないだろうか?

image.png

データは活用しないと意味がない。

ログはS3に集約しよう。

そうしてこそ、分析に活かせたり、運用も一元化できたり、、

何より注目したいのは保管料金だ。
より安価なアーカイブサービスのGlacierの保管も視野に入る。

■CloudWatchの保管料金
0.033 USD/GB

■S3の保管料金
0.025 USD/GB

■Glacierの保管料金
0.005 USD/GB

賢いあなたは1GBにつき、約3円の無駄金を許せないはずだ。

【要件】
毎日0時にLambda関数が起動し、CloudWatchロググループ「cloudwatch-logs-messages」の
前日0:00〜23:59のログをS3のバケット「mys3bucketname/test_prifix」にアップロードする

では、設定していこう。
(というかAWSさん、そろそろこういう機能リリースしてくれないかなー)

S3の設定

保存先のS3バケットにバケットポリシーを付与する

以下を自分の環境に置き換える
- バケット名(以下の例ではmys3bucketnameとしている)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "logs.ap-northeast-1.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::mys3bucketname"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "logs.ap-northeast-1.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::mys3bucketname/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}

Lambdaの作成

python3.6でLambda関数を一から作成する。
(ロールにはCloudWatchLogsの権限とS3の書き込み権限を付与して下さい)

例:S3FullとCloudwatchLogsFUllなど

image.png

Lambda関数を作成する。

以下を自分の環境に置き換える
  - Lambda関数名
  - 保存先S3バケット名
  - 取得するCloudWatchロググループ名
  - 保存先S3バケット名配下の任意のプリフィックス名(任意の名前で構わない)

lambda_function.py
import datetime
import time
import boto3

lambda_name = 'PutLogFromCWLtoS3Function'    #Lambda関数名
log_group_name = '/aws/lambda/' + lambda_name
s3_bucket_name = 'mys3bucketname'    #保存先S3バケット名
s3_prefix = lambda_name + '/%s' % (datetime.date.today() - datetime.timedelta(days = 1))

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      = 'cloudwatch-logs-messages',     #取得するCloudWatchロググループ名
        fromTime          = from_ts * 1000,
        to                = to_ts * 1000,
        destination       = 'mys3bucketname',     #保存先S3バケット名
        destinationPrefix = 'test_prifix'    #保存先S3バケット名配下の任意のサブフォルダ名(プリフィックス名)
    )
    return response

Lambda関数のテストは以下の形で「作成」を押下してOK

image.png

この関数をCloudWatchイベントに登録し、毎日0:00に起動するようにすればOK
(時刻はUTC基準なので気をつける。)

UTC + 9時間 = JST

0 15 * * ? *

CloudWatchイベントの登録方法は以下の記事を参照してみて欲しい。

朝7時にCloudWatchイベントからLambdaを介しAmazon Connectのコールスクリプトを発動し、
バーチャル彼女(女性の機会音声)に事前登録したスクリプトを読み上げさせるモーニングコールを
サーバーレスで設計したものだ。

AWSバーチャル彼女から毎朝モーニングコールで起こしてもらう1つのアーキテクト

おわりに

 ・バケット名、プリフィクス名をパラメーターで渡せば多数のロググループも対応可能と思われる。
 ・日次ではなく、1週間ごとにまとめてアップロードも可能。時間がかかりそうな際はLambdaの実行時間制約に気をつけて(デフォルト3秒となっているので、1分とかに延ばすこと)

ありがとうございました。
少しでもお役にたちましたら「いいね」をよろしくお願いします。

46
41
1

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
46
41