F@N Ad-Tech Blog

株式会社ファンコミュニケーションズ nend・nex8のエンジニア・技術ブログ

ELBのログを見てみた

こんにちは、新人インフラ担当のy_kawasakiです。

先日、AWSのELBがLogをS3に保存してくれるようになりました![1]見てみたかった人も多かったはず。 このログで、下記の項目が見られるようになりました。[2](HTTPのアクセス以外もLogは出ますが、項目は減ります)

  • Load Balancer IP(S3のキー名から)
  • アクセスした時間
  • Load balancerの名前
  • clientのアドレスとポート番号
  • リクエストを処理したserverのアドレスとポート番号
  • ELBがリクエストを受けてから、back endに処理を投げるまでにかかった時間
  • back endに処理を投げてから返事が帰ってくるまでの時間
  • ELBがback endから処理を受け取って、clientに返すまでにかかった時間
  • ELBがclientに返したステータスコード(HTTP Only)
  • ELBがback endから受け取ったステータスコード(HTTP Only)
  • ELBが受け取ったリクエストのサイズ。(ただし、HTTPの場合header部含まず)
  • ELBが返したサイズ。(ただし、HTTPのheader部含まず)
  • リクエストURI(HTTP Only)

というわけで、何はともあれ、設定してみましょう。

設定

  1. マネージメントコンソールから、EC2 -> Load Balancers と選択します。
  2. マネージメントコンソールを最新版にしていない場合は右上の青い吹出しをクリックして最新版にします。 Let's click "Click here"! [caption id="attachment_2819" align="alignnone" width="300"]AWSコンソール AWSコンソール[/caption]
  3. Logを保存したいELBを選択します。
  4. Descriptionの下の方にAccess Logsという項目が出現するので、Editをクリック
  5. 下記のような設定画面が出るので設定します。 [caption id="attachment_2820" align="alignnone" width="300"]アクセスログ保存設定画面 Access Log保存の設定[/caption]
    1. Enable Access Logsのチェックマークを入れる
    2. Interval(ログを吐き出す周期)を設定(5分と60分が選択可能)
    3. S3 Location(保存場所)を設定(Bucket名は必須)
    4. 好みに応じて、Create the location for meにチェックを入れる(これにチェックを入れると、自動でbucketを作りセキュリティ設定まで行ってくれるすぐれもの!)
    5. Saveをクリック
    6. Logが吐出されるまで首を長くして待つ

これで、S3の設定したbucketに保存されるようになったので、あとは、ElasticSearchに入れて、Kibanaに入れて眺めるなり、Amazon EMRに入れて遊ぶなりできるようになります。

ログを良く見てみて、cliとか、で呼ぶとわかるのですが、同じPrefixのものがずらずらと返ってきます。そして、keyには一意に決まるものを渡す必要があります。つまり、3月31日のデータだけ欲しいということができないのです。この辺りは、痒いところに手が届きにくいAWSのツール類という感じです。ファイル数が少ない時は、それでもいいのですが、数が増えてくると大変なことになります。自分は、Pythonで、botoを使っているのですが、呼び出すメソッドによっては、初期設定で1000しか返ってきません。そこで、Prefixを日付にして、保存しなおすツールを作りました。これでprefixが日付になるので、少しは使いやすくなったかな?時間を含めてもいい感じかもしれませんね。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function

import sys
import os
import re
from optparse import OptionParser

import boto.s3.connection

_re_key_name = re.compile('(?P<prefix>.*?)AWSLogs/(?P<account_id>\d+)/elasticloadbalancing/(?P<region>.+?)/'
                          '(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/'
                          '(?P=account_id)_elasticloadbalancing_(?P=region)_(?P<elb_name>[^_]+)_'
                          '(?P<time_stamp>[0-9]{8}T[0-9]{4}Z)_(?P<elb_ip_addr>\d+\.\d+\.\d+\.\d+)_(?P<log_hash>.+)\.log')

def move_key(key, bucket_connection):
    """
    ELBのlogのkeyをよさ気な感じに保存し直す
    """
    _m_key_name = _re_key_name.match(key.name)
    if _m_key_name is not None:
        dst_prefix = ""
        if _m_key_name.group('prefix') != "":
            dst_prefix = "%s-" % (_m_key_name.group('prefix'))

        dst_prefix += "%04d%02d%02d-%s" % (int(_m_key_name.group('year')), int(_m_key_name.group('month')), int(_m_key_name.group('day')), _m_key_name.group('elb_name'))

        dst = "%s/%s_%s_%s.log" % (dst_prefix, _m_key_name.group('time_stamp'), _m_key_name.group('elb_ip_addr'), _m_key_name.group('log_hash'))

        key.copy(bucket_connection, dst)
        key.delete()

        print("%s to %s" % (key.name, dst))

def _check_config_files(parser, options, arg):
    access_key = options.access_key
    secret_key = options.secret_key

    if access_key is None:
        access_key = os.environ.get("AWS_ACCESS_KEY", None)
    if secret_key is None:
        secret_key = os.environ.get("AWS_SECRET_KEY", None)

    if access_key is None or secret_key is None:
        parser.error("AWS Access Key or Secret Key is not Found!!")

    if len(arg) == 0:
        parser.error("requires Bucket Name")

    bucket = arg

    return access_key, secret_key, bucket

def main(access, secret, bucket, prefix):
    s3_connection = boto.s3.connection.S3Connection(access, secret)
    for b in bucket:
        bucket_connection = s3_connection.get_bucket(b)
        for key in bucket_connection.list(prefix=prefix):
                 move_key(key, bucket_connection)

if __name__ == '__main__':
    usage = "usage: %prog [options] bucket"
    parser = OptionParser(usage=usage)
    parser.add_option("-p", "--prefix", dest="prefix",
                      help="Access Log's prefix", default="AWSLogs")
    parser.add_option("-a", "--access-key", dest="access_key",
                      help="AWS Access Key", metavar="", default=None)
    parser.add_option("-s", "--secret-key", dest="secret_key",
                      help="AWS Secret Key", metavar="", default=None)

    (options, args) = parser.parse_args()

    (access_key, secret_key, bucket) = _check_config_files(parser, options, args)

    main(access_key, secret_key, bucket, options.prefix)

使い方は、

$ move.py -p <Prefix> -a <ACCESS KEY> -s <SECRET KEY> bucket

標準の保存keyは、

{Bucket}/{Prefix}/AWSLogs/{AWS AccountID}/elasticloadbalancing/{Region}/{Year}/{Month}/{Day}/{AWS Account ID}_elasticloadbalancing_{Region}_{Load Balancer Name}_{End Time}_{Load Balancer IP}_{Random String}.log

が、

{Bucket}/{Prefix}-{Year}{Month}{Day}-{Load Balancer Name}/{End Time}_{Load Balancer IP}_{Random String}.log

になります。

これを元にfluentdでelasticsearchに投げて、Kibanaで表示でもいいかもしれません。

Reference: