いわさです。
Amazon CloudWatch Logs Insighs では専用のクエリ構文を使うことで CloudWatch ロググループのログをクエリすることが出来ます。
クエリにちょっと癖がありますが、複雑なクエリを実施することが出来るためログの分析や簡易的に統計を取ったり、トラブルシューティングを行う際に重宝します。
大量のログが出力されるため、ある程度グルーピングや不要な情報の除外を行いたいところですが、これまでは stats コマンドでグルーピングを駆使することで頑張って重複を排除する方法がありました。
今回のアップデートで重複排除のコマンドとして dedup コマンドが使えるようになりました。
dedup コマンド
公式ドキュメントのリファレンスは以下です。
コマンドなので、位置づけとしてはfilter
やsort
などと同列です。
使い方は非常にシンプルで 1 つ以上のフィールドを指定することで、対象フィールドの値が重複している行は排除されます。
重複排除のルールとしてはソート順の最初の行のみが保持され以降の重複行は排除されます。
また、フィールドを複数指定した場合は複数フィールドの組み合わせを以て一致していると見なされます。
使ってみる
私は普段検証用に CloudFormation で EC2 を作成するときは次のように Apache をインストールして CloudWatch エージェントをセットアップしアクセスログをロググループへ転送するインスタンスをデフォルトで使っています。(以下はユーザーデータ部分のみを抜粋。テンプレート全体はこちら)
WebServer:
Type: AWS::EC2::Instance
Properties:
InstanceType: t3.small
:
UserData:
Fn::Base64: |
#cloud-config
package_update: true
package_upgrade: true
runcmd:
- yum update -y
- yum install httpd -y
- service httpd start
- chkconfig httpd on
- echo "hoge" > /var/www/html/index.html
- [ sh, -c, "rpm -Uvh https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm" ]
- /opt/aws/amazon-cloudwatch-agent/bin/config-translator --input /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json --output /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml --mode ec2
- /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a start
write_files:
- path: /var/www/html/index.html
permissions: 0644
owner: root
content: |
hoge.html
- path: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json
owner: root
group: root
mode: '000600'
content: |
{
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/httpd/access_log",
"log_group_name": "/var/log/httpd/access_log",
"log_stream_name": "{instance_id}"
},
{
"file_path": "/var/log/httpd/error_log",
"log_group_name": "/var/log/httpd/error_log",
"log_stream_name": "{instance_id}"
}
]
}
}
}
}
上記の構成の場合、対象のロググループでは次のようにインスタンス ID がログストリーム名が作成されて、インスタンスごとにログが出力される形となります。
まずは、上記に対して次のようにデフォルトでログ検索を行ってみます。
fields @timestamp, @message, @logStream, @log
| sort @timestamp desc
| limit 20
タイムスタンプの降順で出力しているので、ログストリーム(インスタンス)ごとには確認が出来ません。
例えば、もしインスタンスごとに最後にアクセスがあった内容は何かを把握したい場合はこれだと都合が悪いです。
dedup を使ってインスタンスの重複を排除してみる
これを次のようにdedup
でログストリームフィールドを指定すると、同一ログストリームで 1 行のみログが出力されます。
タイムスタンプの降順でsort
にした後にdedup
しているので、ログストリームごとに最新の 1 行のみが出力される形です。
fields @timestamp, @message, @logStream, @log
| sort @timestamp desc
| dedup @logStream
| limit 20
良いですね。
インスタンスごとの最後のアクセスログの内容がわかるようになりました。
ほとんどが ALB からのヘルスチェックアクセスのログなのでこれは除外しましょう。
先程のsort
と同じで、条件や並び替えの後に重複排除します。
fields @timestamp, @message, @logStream, @log
| sort @timestamp desc
| filter @message not like "ELB-HealthChecker/2.0"
| dedup @logStream
| limit 20
良さそうです。
おそらく今までだと次のようにstats
コマンドとlatest
関数を組み合わせるとか、そういったやり方が多かったのではないでしょうか。
fields @timestamp, @message, @logStream, @log
| sort @timestamp desc
| filter @message not like "ELB-HealthChecker/2.0"
| stats latest(@timestamp), latest(@message) by @logStream
| limit 20
集計とか不要で重複の排除だけをシンプルに行いたかったので、これは非常に使いやすいです。
さいごに
本日は Amazon CloudWatch Logs Insights で重複排除を行う dedup がサポートされましたので使ってみました。
頑張れば従来でもクエリ自体は出来ていたと思いますが、より直感的で使いやすくなって良いですね。