AWS
fluentd
lambda

CloudWatchLogsAPIとfluent-plugin-s3を使ったLambdaログの保管と分析、可視化について

はじめに

これは、Sansan Advent Calendar 2017の24日目の記事です。

  • CloudWatchLogsはログを時系列で絞込検索がしにくいとか、見にくいし使いにくいツールである
  • 本番でLambdaの関数がxx 個以上動いており、障害発生時の調査にはCloudWatchLogsを頑張って使うしかない
  • apexでログを見る方法もないわけではないが、ずっとtailするのは難しい
  • CloudWatchLogsにずっと置いとくのもアレ
  • CloudWatchLogs早くいい感じになって欲しい

ということですでにfluentdなどで収集しているアプリケーションログやアクセスログと同様にS3に保管し、Elasticsearchに乗せてKibanaで検索、分析できるようにしたかったのです。CloudWatchLogsAPIとfluent-plugin-s3を使ってLambdaログの保管と分析、可視化をできるようにしました。

あきらめた案

fluent-plugin-cloudwatch-logsで収集しようともしていました。しかし、新たに生み出されるLogStreamの収集ができず、理由もよくわからず断念した。fluentdをpryで止めて結構デバッグしたものの、fluentd力もっとほしい…!となりました。
Lambdaのログは、CloudWatchLogsのLogGroup以下にLogStreamとしてつくられていくが、LogStreamに[$LATEST]というLambdaのバージョンプレフィックス的なやつが入るため、fluentdのbuffer_path設定と相性が悪かったです。(この仕様マジでやめてほしい。括弧とかドル記号とか入らないでほしい。)
また、50個以上のLogStreamsがある際に、このpluginではログを扱うArrayが予期せぬ入れ子構造になってしまっていたため修正しました。
どちらもマージされてはいるが、力不足によりこのプラグインでは収集を完遂できませんでした。

https://github.com/ryotarai/fluent-plugin-cloudwatch-logs/pull/80
https://github.com/ryotarai/fluent-plugin-cloudwatch-logs/pull/84

詳細な説明

ピタゴラ装置

Lambda

まずは、CloudWatchLogsのAPIを叩くためのLambdaをつくりました。Python3.6で実装しました。
このLambdaは、CloudWatchLogs.Client.create_export_taskを叩いています。
http://boto3.readthedocs.io/en/latest/reference/services/logs.html#CloudWatchLogs.Client.create_export_task

しかし、エクスポート対象にする期間の指定はコード上に置いておきたくありませんでした。(create_export_taskのfrom, toの指定)
そのため、前回実行時のタイムスタンプをS3上に置くようにし、これが無ければ現在からn時間分エクスポートし、あればfromにセットするという実装にしました。こうすることで、実行タイミングはCloudWatch EventsのRuleのみで与えられるようになります。

Lambdaの周辺

fluent-plugin-s3では、S3からログを取り込むことができます。S3イベント通知でSQSに流しています。あとはわりと普通です。

cloudwatchlogs-import-after.png

ちなみに

アレがこれであーなので、実はあと一歩のところで本番投入できていません。年内にはやっておきたいです。
現在の職場での特異的な話が絡むfluent-s3-plugin関連の設定についてなので、根底から覆るような話ではありません。もし同じような構成を考えている人がいたら安心してほしいです。

最後に

CloudWatchLogsが使いやすくなることや、Lambdaのログが自動的にS3へエクスポートし続ける設定がほしいです。LambdaのためにLambdaを作ることが減るといいなぁと思いますので、サンタさん(AWS)何卒よろしくお願いします。