[アップデート] Amazon CloudWatch Logs Insights で重複排除を行う dedup がサポートされました

2023.06.21

いわさです。

Amazon CloudWatch Logs Insighs では専用のクエリ構文を使うことで CloudWatch ロググループのログをクエリすることが出来ます。
クエリにちょっと癖がありますが、複雑なクエリを実施することが出来るためログの分析や簡易的に統計を取ったり、トラブルシューティングを行う際に重宝します。

大量のログが出力されるため、ある程度グルーピングや不要な情報の除外を行いたいところですが、これまでは stats コマンドでグルーピングを駆使することで頑張って重複を排除する方法がありました。

今回のアップデートで重複排除のコマンドとして dedup コマンドが使えるようになりました。

dedup コマンド

公式ドキュメントのリファレンスは以下です。

コマンドなので、位置づけとしてはfiltersortなどと同列です。

使い方は非常にシンプルで 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 がサポートされましたので使ってみました。
頑張れば従来でもクエリ自体は出来ていたと思いますが、より直感的で使いやすくなって良いですね。