S3にエクスポートされたCloudWatch LogsのファイルをGlueのCrawlerでETLしようとして轟沈した話
S3にエクスポートした CloudWatch Logs のログストリームをAWS GlueでETLしようと挑戦してみました。 結論から言うと、GlueのCrawlerでログをいい感じにパースできなかったので、失敗しました、という話です。
モチベーション
S3のファイルをETLしたい
「 Step FunctionsでCloudWatch LogsのロググループをS3へエクスポートする 」 の記事にて、 CloudWatch LogsのログストリームをS3へエクスポートしました。
次のステップとしては、データ分析しやすいようにETLしようというわけです。
ETLといえばGlue
AWS上でETL処理を行うのであれば、聞いたことがあるのはやはり AWS Glue でしょう。
Apache Sparkをベースとしており、せっかくだから使ってみたかったわけです。
やってみよう
以下のような構成で処理させようと考えていました。
基データのログフォーマット
CloudWatch LogsはログデータがJSONフォーマットになっていると、 JSON pathのような検索ができたり、ログを展開したときにpretty printしてくれるのでよく使ってしまいます。
今回処理させたいデータも、この JSONフォーマットのログをCloudWatch Logsのエクスポート機能でS3にファイル出力したもの です。
Crawlerの設定でつまずく
AWS Glue と Amazon S3 を使用してデータレイクの基礎を構築する にも記載がありますが、 Glueには Crawler という設定があり、指定したデータソースの更新を確認し、データカタログを よしなに作ってくれる機能 があります。
ただ、どう「よしなに」作ってくれるかというと、 公式ドキュメント 記載の通り、テキストのフォーマット毎に指定のロジックがあり、それに準じて処理するデータ形式を判断しているようです。
これを見て 「よっしゃ、いい感じにJSONになるのね」 と早合点して、ポチポチ設定を進めていったのが問題でした。
ログフォーマットが変わっている?
Crawlerが S3バケットのファイルからデータカタログを作成してくれたわけですが、以下のように 「ion でした」 という結果が出てきました。
「あれ?jsonではないの?」
そう思って、S3上の .gz ファイルの中身を見てみると以下のような形式になっていました。
12018-05-27T00:00:00.107Z {ログのJSON文字列}
22018-05-27T00:01:36.107Z {ログのJSON文字列}
3(以下略)
CloudWatch Logsからログデータをエクスポートすると、タイムスタンプ情報も出力されてしまい、 JSON形式でなくなっていた わけですね。
Grokも模索してみたが。。
Crawlerがログファイルを分類するために、自前の カスタム分類子 を設定することもできます。
- Grok
- XML
- JSON
の3つが定義されているのですが、XMLとJSONはすでにテキスト形式がそのフォーマットに加工されている必要があるので、使えそうにありません。 よく Log Stash などで使われる Grok形式 が一番カスタマイズ性が高いのですが、この設定を用いても 要素が可変になるJSONを処理することはできませんでした。
サポートにも相談してみたが。。
「私のGlueの設定が悪いのかも」と一縷の望みを託して、AWSのサポートにも聞いてみたのですが、「Glue単体で今回のログフォーマットは処理できない」と回答をいただきました。
まとめ
GlueのCrawlerでいい感じにデータカタログを作るのに失敗しました。
デフォルトの分類子、または、自前で定義したカスタム分類子によってGlueのCrawlerはデータカタログを作成してくれます。 しかし、すべてのフォーマットに対して柔軟に処理できるわけではないので、フォーマットによってはGlueが処理しやすいように前段で自前ETLを挟んであげる必要がありそうです。
特に今回のような、 CloudWatch LogsのログがJSON形式で、エクスポート機能でS3に外出ししたファイル(ログの一部がJSON形式) の場合には相性が悪いということがわかりました。