CloudFrontログをCloudWatch Logsに流してターミナルで確認してみる

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

どうも!大阪オフィスの西村祐二です。

突然ですが、CloudFrontのログをどうやって確認していますか?

CloudFrontのログはS3にgzip形式で出力されるので、
ファイルをローカルに落としてきて、ツールに入れて確認や、
EMRやAthenaを使って確認などいろいろ方法がありますが、
手間がかかったり、すこし大げさな感じがしています。

個人的にはターミナルでパイプでつないでgrepawkとかで確認できたらいいなと思っていました。
そんな中、社内のAWSのプロ達にきいたところ良さそうな方法を教えてもらったのでブログにしてみたいと思います。

簡単に要点をまとめると

  • Serverless FrameworkでS3上のgzipを読み取りCloudWatch Logsに出力するLambda関数を作る
  • S3(CloudFrontログ出力先)にログファイルがおかれたら、Lambdaを実行されるように設定しておく
  • Serverless Frameworkのログ確認機能を使って、CloudFrontのログが出力されたLambdaの実行ログをターミナルで確認する

ポイントはServerless Frameworkのログ確認機能です。
作成したLambda関数のログを簡単に確認できます。
これは一度設定しておくだけ、ターミナルでCloudFrontのログが確認できるようになります。
また、パイプでつないでgrepawkなども使えます。

※ログ量が増えてくると、CloudWatch Logsの料金が膨らんできてしまうので注意

さっそくやっていきましょう!

環境

  • node.js : v9.6.1
  • Serverless Framework : 1.26.0

Serverless Frameworkをインストール

$ npm install -g serverless

Serverless FrameworkでLambda関数を作成

▼ まず、プロジェクトを作成します。言語は「python3.6」です。

$ sls create --template aws-python3
Serverless: Generating boilerplate...
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.26.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-python3"
Serverless: NOTE: Please update the "service" property in serverless.yml with your service name

$ ls
handler.py     serverless.yml

▼ テンプレートファイルを編集していきます。

$ vi serverless.yml

トリガーのS3バケットを指定している
test-cf-accesslog-watch-nishimuraは自分の環境へ置き換えてください。
すでに作成済のバケットだとエラーになるので、ご注意ください。
ここで指定したバケットをCloudFrontログの出力先とする想定です。

service: access-log-watch # NOTE: update this with your service name
frameworkVersion: ">=1.26.0 <2.0.0" 

provider:
  name: aws
  runtime: python3.6
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "s3:GetObject"
      Resource:
        - "arn:aws:s3:::*"
package:
  exclude:
    - "**"
  include:
    - logwatch.py

functions:
  func:
    handler: logwatch.lambda_handler
    events:
      - s3:
          bucket: test-cf-accesslog-watch-nishimura
          event: s3:ObjectCreated:*

▼ Lambda関数のプログラムを作成します。

$ vi logwatch.py

行っている処理としては、S3に保存されたオブジェクト(gzipファイル)を取得して、
printでログ出力しているだけです。

import boto3
import gzip
import urllib.parse

S3 = boto3.resource('s3')
S3CLIENT = boto3.client('s3')

def getobject(bucket, key):
    """
    Get S3 object
    """
    S3CLIENT.download_file(bucket, key, '/tmp/access-log.gz')
    with gzip.open("/tmp/access-log.gz", "rt", "utf_8") as fi:
        for line in fi:
            print(line)

def lambda_handler(event, context):
    """
    main
    """
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(
        event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    try:
        getobject(bucket, key)
    except Exception as e:
        print(e)

▼ デプロイ

$ sls deploy -v

Lambda関数が作成されていること、権限周りが付与されていることを確認します。

CloudFrontのログ出力先を変更

CloudFrontのマネージメントコンソールから対象のDistributionを選択し、「Edit」ボタンをクリックします。
下部のLoggingあたりの設定を行います。「Bucket for Logs」にはLambdaのトリガーとなるバケットを指定します。

動作確認

▼ S3にCloudFrontのログ(gzipファイル)がPUTされると、Lambdaが実行され、CloudWatch Logsにログ内容が出力されます。

ターミナルでログ確認

Serverless FrameworkでLambdaのログを確認することができるので、この機能を利用します。

  • Lambdaのログ確認コマンド

このコマンドは、1MBに収まるログイベント数(最大10,000ログイベント)を返します。

funcのところにはテンプレートファイルで設定したファンクション名を指定してください。

$ sls logs -f func

下記画像のようにログが出力されます。

この出力されたログに対してパイプしてgrepなど利用することが可能ですが、
Serverless Frameworkのオプションを指定することでも実現可能です。

よく使いそうなオプションをまとめておきます。

  • -tオプションでtail -fのような確認ができます。
$ sls logs -f func -t
  • --filterオプションで取得するログの絞込ができます。

ログに「2018-02-26」が含まれているログだけ取得されます。

$ sls logs -f func --filter 2018-02-26
  • --startTimeオプションでログの取得期間を指定することができます。

過去5時間以内に発生したログが取得されます。

$ sls logs -f func --startTime 5h

詳細は下記をご確認ください。
https://serverless.com/framework/docs/providers/aws/cli-reference/logs/

さいごに

いかがだったでしょうか。

Serverless FrameworkとLambdaを使って
CloudFrontログをCloudWatch Logsに流してターミナルで確認できるようにしてみました。

Serverless Frameworkを使ったことがある方ならすぐできると思いますので、
CloudFrontのログ確認を手軽にしたいなと思っている方はためしてみてはいかがでしょうか。

誰かの参考になれば幸いです。