ナスです。

Cloudwatch logs のログを Elasticsearch Service に転送するの、簡単でいいですね。対象のロググループのアクションで、「Stream to Amazon Elasticsearch Service」を選べばいいだけですから。

CloudWatch Logs サブスクリプションを通して、ほぼリアルタイムでAmazon Elasticsearch Service (Amazon ES) クラスターで受け取るCloudWatch Logs ロググループをストリームデータに設定することができます。詳細については、「 」を参照してください。

docs.aws.amazon.com

でも、それで作成される Lambda Function が完璧かというとそうでもありません。残念ながらいろいろと調整しないといけないです。というか本番環境でそのまま使えた試しがまだ一回もないです… 使い方が悪いのかな。

Apache のアクセスログだけたまにエラーで転送されない

という事象に出くわしました。本当にたまにです。Elasticsearch Service に転送する Lambda のログを見ると、こんなエラーでした。

2017-04-19T00:00:00.700Z   xxxxxxxxxxxxxx    Failed Items: [
{
    "index": {
        "_index": "cwl-access_log-2017.04.19",
        "_type": "/var/log/httpd/access_log",
        "_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "status": 400,
        "error": {
            "type": "mapper_parsing_exception",
            "reason": "failed to parse [bytes]",
            "caused_by": {
                "type": "number_format_exception",
                "reason": "For input string: \"-\""
            }
        }
    }
}
]

ちなみにログ転送する際に定義したフィルタは↓これです。

[host, id, user, date, request, status, bytes, other]

bytes に入れようとした値が -(ハイフン) だったので、それ数値じゃねーよ!って言われてます。

対処は簡単

対処法は 2 つあります。

1 つは、Lambda で bytes にあたる値が “-” だったら 0 にする。もう 1 つは、httpd 側でログフォーマットを変更する。です。

httpd のログフォーマットについては、ここをみれば ok です。
ログファイル – Apache HTTP サーバ バージョン 2.2

該当の説明を見ると、

この最後のエントリはクライアントに送信されたオブジェクトの、 応答ヘッダを除いたサイズを表します。コンテントがクライアントに送られなかった 場合は、この値は “-” になります。コンテントが無い場合に “0” をログ収集するには、%b ではなく %B を使ってください。

とありますので、ログフォーマットを %B に変更してやればいいわけです。結局、Lambda 側で調整することにしたので、httpd のログフォーマットで調整できるかどうかは試していませんが、たぶんできると思います。

 
この件で思ったのは、ログファイルごとにログフォーマットがちゃんと揃ってないと Elasticsearch Service に転送する時にエラーが出まくることになるので、注意が必要だということです。ミドルウェア等のログフォーマットはだいたい揃っていると思いますのでいいのですが、自社や他ベンダーが開発したアプリケーションのログも Elasticsearch Service に転送するなら、ログフォーマットがどうなっているかよく調べたほうがいいと思います。

元記事はこちら

Apache のアクセスログでオブジェクトサイズが “-” になってた [cloudpack OSAKA blog]