CloudWatch logsのログをinsightで検索

ログについては、ひとまずCloudWatch logsに投げ込む運用にしています(注1

このCloudWatch logsを高速に検索できるインサイトをCLIから使う紹介です( WEBでの使い方については[ CloudWatch ]->[ インサイト ]でいろいろ試していただきたいです ) 障害調査の場合、どのみちgrepすることになるのでCLIでの手順も残しておきます。

ログ取得

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatchLogs/latest/APIReference/API_StartQuery.html

--start-time 開始時刻をunixtime
--end-time 終了時刻をunixtime
--query-string 参考 https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html

クエリ(フィルタリング)について

検索する際の方法 limit 10 とか。

このためにインサイトを使っていると言えますが正規表現

| filter @message like /access_token=/

クエリ例

参考: サンプルクエリ - Amazon CloudWatch Logs

nginxのログのみを表示する

| filter @logStream LIKE /nginx/

ロードバランサからのヘルスチェックを除外する

| filter @message NOT LIKE /ua:ELB-HealthChecker/

ステータスコードが500番台のもののみを表示する

| filter @message LIKE /status:5\d+/

ログをパースして変数にセットする

| parse @message "time:*host:*forwardedfor:*req:*status:*size:*referer:*ua:*reqtime:*cache:*runtime:*vhost:*userid:*" as time, host, forwardedfor, req, status, size, referer, ua, reqtime, cache, runtime, vhost, userid

クエリ実行( ログ検索は時間がかかるため、後で別途getする必要があります)

bash環境(dateコマンドはbrewのcoreutilsを使用)

クエリ実行

aws logs start-query --log-group-name NginxApiAccessLog --start-time $(date +%s --date "2019-02-01 00:00") --end-time $(date +%s) --query-string 'fields @timestamp, @message | sort @timestamp desc | limit 10000'

を実行すると

クエリIDが帰る。

{
    "queryId": "294ef35e-f602-46f9-b63c-a3abc12135a1"
}

結果取得

–query-id に上記で得たクエリIDを渡します。

aws logs get-query-results --query-id '63c8c0bc-7c17-4d92-87b0-f4d71d6c85b5'  | jq '.results[][] | select(.field == "@message") | .value'

「WebUIでクエリIDを取得したい」

クエリの試行錯誤はWebUIの方が楽だったり、チェックしやすかったので「WebUIでクエリを組み立て実行」「結果はCLIから取得、手元でgrep」の方が早く作業できる場合もあります。 この場合ですが、2019/02時点では WebUIではクエリIDを確認する方法がありませんでした。

aws logs describe-queries

で、確認できます。

WebUIでの検索

  • 右上のAWSアカウントをクリック、ロールを必要に応じて変更
  • https://ap-northeast-1.console.aws.amazon.com/cloudwatch/ を開く
  • 左のメニューから インサイト を選択
  • ロググループをプルダウンメニューから選択( ここでは /ecs/env25 を選択しています )
  • フィルタルールを追加

例えば php-fpmのエラーログを探したい 場合では

fields @timestamp, @message
| sort @timestamp desc
| filter @logStream LIKE /php-fpm/
| filter @message NOT LIKE /200$/
| limit 100

料金

https://aws.amazon.com/jp/cloudwatch/pricing/ 1 GB あたり 0.0076 USD です。 ざっくりとで構いませんので期間の指定で絞ってください。 ただ各自の時給と比較すると安くなると思います(CloudWatch logsをエキスポートしてMacで検索するのは、それなりに時間がかかる)

注1) ほかの選択肢、例えばfluentdエージェントを運用してs3に転送する方法も行っていました ( 導入自体は簡単にできます https://dev.classmethod.jp/cloud/aws/fluentd-s3/ )

が、意外とアクセスが増える瞬間、あるいはfluentdのルールを複雑にするとfluetndの負荷が気になってきます。 fluentエージェントのCPU負荷を下げるためには別途、フィルタリング用のfluentdを別インスタンスで立てる必要になり…という形で、 関連する運ソースの増大が見えてきため、AWS標準のCloudWatch logsに転送するようにしています。 ( ただインスタンス数が増大するなどした場合は、この辺の共有で使う運用リソースのコストは、全体に均されていきます。 CloudWatch logsと人件費を比較しfluentd導入を再検討するのもありな状況もあります )

User
CloudFront
ALB
EC2
RDS