この記事は、ソニックガーデン プログラマ Advent Calendar 2024の14日目の記事です。
TL;DR
AWS CloudWatch Logsのログのインサイトを使うことで、Railsアプリケーションのログを高速に検索し、解析できます。特定の条件でログを絞り込んだり、JSON形式のデータを解析して必要な情報だけを抽出したりするなど色々な活用が可能です。ただし、スキャンするデータ量に応じて料金が発生するため注意が必要です。
背景
RailsアプリケーションのほぼJSON形式のログをAWSのCloudWatch Logsに保存しています。アプリケーションログは必要に応じて絞り込んで閲覧したいケースがよくありますが、単純な検索ではログの分量が多い場合に時間がかかりすぎることがあります。
「ログのインサイト」とは?
「ログのインサイト」はCloudWatch Logsの機能の一つで、以下のようなメリットがあります:
- ログの高速検索
- ログ内容の解析や計算による絞り込み・出力
- 必要な項目だけをSQL風のクエリで選択して出力
- 出力結果をCSV形式などでダウンロード
「ログのインサイト」はCloudWatchのサイドメニューからアクセスできます。
基本操作
ログのインサイトを開くとこのような初期画面が現れます。
- 検索期間を指定する
- タイムゾーンを必要に応じて変更する
- ロググループを選択する
- クエリを入力する
- 実行する
- 結果が表示される
- 必要なら結果をダウンロードやコピーする
またクエリには次のようなものがプリセットされています。
fields @timestamp, @message, @logStream, @log
| sort @timestamp desc
| limit 10000
ログ解析の実例
いくつかの例を紹介する前に、今回解析の対象とするログ形式を明確にておきます。
Railsでlograge gemを使用し、以下のようなJSON形式をログを解析することとします。
(横に長いので表示ために改行をいれています)
I, [2024-12-06T09:56:24.761724 #42]
INFO -- : [ec002d16-7b40-4fac-8bf7-f873e56b1234]
{"method":"GET","path":"/","status":200,"duration":156.93,
"remote_ip":"127.0.0.1","user_agent":"Mozilla/5.0","params":{}}
■特定の文字列にマッチするログを抽出
例)UsersControllerが処理したリクエスト
fields @timestamp, @message, @logStream, @log
| filter @message like /UsersController/
| sort @timestamp desc
| limit 10000
■ 特定のフィールドを切り出して絞り込み
例)duration(レスポンスにかかった時間)が10秒以上のリクエスト
fields @timestamp, @message, @logStream, @log
| parse @message '"duration":*,' as @duration
| filter @duration > 10000
| sort @timestamp desc
| limit 10000
■ 特定のフィールドを切り出して、さらに式を適用して条件にしたい
例)user_nameにマッチした文字列が10文字より大きいリクエスト
fields @timestamp, @message, @logStream, @log
| parse @message '"user_name":*,' as @user_name
| filter strlen(@user_name) > 10
| sort @timestamp desc
| limit 10000
■ 特定の行を除外したい
例)ActiveJobの実行ログや手動で書き出しているログを除外する
fields @timestamp, @message, @logStream, @log
| filter @message not like /Job|\[INFO\]/
| sort @timestamp desc
| limit 10000
■ JSONとしてパースして検索する
fields @message
| parse @message 'I, [*] INFO -- : [*] *' as _, @request_id, jsonPart
| fields jsonParse(jsonPart) as json
| filter json.method like /GET/
| sort @timestamp desc
| display @timestamp, @request_id, json.action, json.method, json.duration
jsonParseにJSONの文字列を渡すことでjsonとして解釈できるようにし、json.method
やjson.duration
のようにアクセス可能になります。これが非常に便利。今回の本題といっても過言ではありません。
注意点: 料金の発生
「ログのインサイト」は、スキャンするデータ量に応じて料金が発生します。公式ページによると、ログを1GBスキャンするごとに $0.0076 かかります。
Amazon CloudWatch Pricing – Amazon Web Services (AWS)
Query (Logs Insights) $0.0076 per GB of data scanned
大量のログを検索すると予想以上の料金が発生する可能性があるため、注意してください。