Amazon CloudWatch Logs でログを読むために学んだ手法をいくつかメモします。
あまり高度な機能は利用せず、ECS や Lambda をほぼデフォルト設定で使って出力されたログを調査するような想定です。
前提となる概念について
CloudWatch でログを読む際には「ログイベント」、「ログストリーム」、「ロググループ」の概念について意味を理解している必要があります。
下記のドキュメントを引用しつつ、ごく簡単に各概念を説明します。
ログイベント
ログイベントは、モニタリングされているアプリケーションまたはリソースによって記録されたアクティビティのレコードです。
AWS のコンソール画面ではこの画像のように表示されます。画像の各行がそれぞれログイベントです。
ログストリーム
ログストリームは、同じソースを共有する一連のログイベントです。
要するにログストリームとはログイベントが集まったもののようです。
画像の各行が一つ一つのログストリームです。
ロググループ
ロググループは、保持、監視、アクセス制御について同じ設定を共有するログストリームのグループを定義します。
ロググループはログストリームの集まりです。画像の各行が一つ一つのロググループです。
まとめると 3 つの概念はLog events
∈ Log streams
∈ Log groups
となると思います。
CLI でログを読む
もちろんコンソール画面からでもログを読むことはできますが、CLI のほうが便利なときもあります。
AWS CLI の CloudWatch Logs 関連コマンドをいくつか紹介します。
- 本稿はバージョン
2.3.1
で確認しています。 - AWS CLI はデフォルトでは JSON で結果を出力します。しかし、JSON で出力されると人間には読みにくいです。そのため、
--output text
を指定して多少読みやすい形式で出力させています。 - 必要な情報のみを取得するために
--query
を指定してフィルタリングしています。このクエリは JMESPath という構文が使われています。jq で使うルールと似ていますが、少し違うものです。 - Lambda のログストリーム名などは「$」が含まれることがあります。その場合適宜シングルクォーテーションで囲むなどしてください。(でないと変数展開しようとされます)
ロググループを一覧にする
aws logs describe-log-groups --query "logGroups[].[logGroupName]" --output text
ログストリームを一覧にする
--log-group-name
の後ろに対象のロググループを指定します。
aws logs describe-log-streams --log-group-name /ecs/hello-spring --query "logStreams[].[logStreamName]" --output text
ロググループ、ログストリームを指定して読む
--log-group-name
と--log-stream-name
を指定します。
aws logs get-log-events --log-group-name /ecs/hello-spring --log-stream-name ecs/minimal-spring/f4dd8cd7-0943-4a4f-b3b4-a13b7e5d9701 --query "events[].[message]" --output text
tail する
tail -f
のように追記を追いかけて CloudWatch のログを読むこともできます。
aws logs tail --since 5m --format short --follow /ecs/hello-spring
-
--format short
すると TimeStamp などの表示が消え、見やすくなります。 - since でその名の通りいつからのログを表示するか指定できます。デフォルトは 10 分です。
ログをファイルでダウンロードする
実は前述のget-log-events
コマンドではあるログストリームのログをすべて取得できるとは限りません。
AWS CLI のドキュメントには
By default, this operation returns as many log events as can fit in a response size of 1MB (up to 10,000 log events).
とあり、最大 1MB、もしくは 10,000 ログイベントしか取得できないようです。しかし、目 grep したい、オンプレのログファイルに対して行っているようなシェル芸を実行したい、などといったときにログ全体が必要になることもあります。
この問題に直面する人は少なくないようで、検索するといくつかダウンロード方法を紹介するブログなどが見つかります。
Qiita だと例えば
がログをローカルにダウンロードする Python スクリプトに関する記事になっています。
この記事のPythonスクリプトを使うとログをダウンロードすることが可能です。
CloudWatch Logs Insights を使ったログの検索
ログを検索したい、と思った場合、AWS コンソール画面でも各ログストリームのページに「インベントをフィルター」というフォームがあり、ログを検索できるようになっています。
しかし、ログが多いと重すぎるのか結果がなかなか返ってこなかったり、返ってこなかったりと不便です。
このような場合に CloudWatch Logs Insights を使った検索が便利です。
ロググループに対して独自の文法によるクエリを発行できます。「インベントをフィルター」よりも動作が軽く、ログが多くてもきちんと結果が返ってきます。
特定ワードで検索するなら下記のようなクエリをクエリ入力フォームに書きます。
fields @message,@logStream
| filter @message like "HikariPool-1"
| sort @timestamp
| limit 25
fields
には取得して表示するフィールドを記載します。SQL の SELECT 句に近いです。
フィールドを複数にする場合は、
fields @message,@logStream
のようにカンマ区切りにします。
@message
はデフォルトで自動的に用意されるフィールドで「生の未解析のログイベント」を表します。(参考:サポートされるログと検出されるフィールド)
要するに該当したログが表示されます。
filter
はその名の通りフィルタリングを行います。高度な指定が可能らしいですが、grep したいだけならば非常にシンプルな判定のみで十分です。
想像できると思いますが、@message like "HikariPool-1"
で部分文字列の一致のチェックを行っており、ログにHikariPool-1
という文字列があれば対象となります。
sort
はその名の通りソートします。SQL と同じように asc と desc を指定でき、デフォルトだと asc(昇順)になるようです。
limit
も SQL と同じように返される結果の数を指定します。
「ロググループを選択」プルダウンでロググループを選択(複数可)し、「クエリの実行」ボタンを押下すると、例えば下記のような結果が取得できます。
あるロググループ中でHikariPool-1
という文字列を含むログイベントが検索できました。
画像だと fields
に@message
だけを指定して実行していますが、@logStream
も指定するとどのログストリームに所属するログイベントかも一目でわかる上に、クリックするとそのログストリームに遷移できるようにもなるため便利です。