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


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

![image.png](https://qiita-image-store.s3.amazonaws.com/0/276897/ae52103f-d0d9-a83f-59a9-12332252728f.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の権限とS３の書き込み権限を付与して下さい）

例：S3FullとCloudwatchLogsFUllなど

![image.png](https://qiita-image-store.s3.amazonaws.com/0/276897/c1613c59-d3ca-efce-bfa9-b8a79016525c.png)

Lambda関数を作成する。

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

```python:lambda_function.py
import datetime
import time
import boto3

lambda_name = 'PutLogFromCWLtoS3Function'    #Lambda関数名
log_group_name = '/aws/lambda/' + lambda_name
s3_bucket_name = 'mys3bucketname'    #保存先S３バケット名
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',     #保存先S３バケット名
        destinationPrefix = 'test_prifix'    #保存先S３バケット名配下の任意のサブフォルダ名（プリフィックス名）
    )
    return response
```


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

![image.png](https://qiita-image-store.s3.amazonaws.com/0/276897/89c40942-fd04-f9fe-0288-0be5b5e8d5cf.png)

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

UTC + 9時間 = JST

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

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

###[AWSバーチャル彼女から毎朝モーニングコールで起こしてもらう1つのアーキテクト](https://qiita.com/blackriver/items/639b0d58b8b59e008e30)

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



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