cloudwatch 統合エージェントから cloudwatch logs にログ転送する際に `InvalidSequenceTokenException`

cloudwatch logs にエージェントからログ転送する際に以下のような Exception が発生するケースがあります。 せっかく support に問い合わせて聞いたのでログに残しておく。

2020-07-06T09:48:26Z W! cloudwatchlogs: InvalidSequenceTokenException, will search the next token and retry the request: The given sequenceToken is invalid. The next expected sequenceToken is: 49607253157850794113694120142050130960625703845569297394, original error: "InvalidSequenceTokenException: The given sequenceToken is invalid. The next expected sequenceToken is: 49607253157850794113694120142050130960625703845569297394\n{\n  ...., {
  RespMetadata: {
    StatusCode: 400,
    RequestID: "f9c433f6-cf15-4dc3-b75d-eca8067f4fac"
  },
  ExpectedSequenceToken: "49607253157850794113694120142050130960625703845569297394",
  Message_: "The given sequenceToken is invalid. The next expected sequenceToken is: 49607253157850794113694120142050130960625703845569297394"
}

aws 公式ドキュメントを見ると、以下のようなケースで発生するらしい

  • 単一のログストリームへ複数ログ(ファイル名が別々なログ)を転送したケース

複数のログファイルからログを単一のログストリームにプッシュすることはできません。設定を更新して、各ログをログストリーム - ロググループの組み合わせにプッシュします

InvalidSequenceTokenException は、ワイルドカードでファイルパスを指定したケースでも該当することがあります。公式では以下のような挙動をすると記述されております

CloudWatch Logs にプッシュするログファイルを指定します。 ファイルは、特定のファイルまたは複数のファイルを指すことができます(/var/log/system.log* のようにワイルドカードを使用)。 ファイルの変更時間に基づいて、最新のファイルのみが CloudWatch Logs にプッシュされます。 access_log.2014-06-01-01 と access_log.2014-06-01-02 など同じ形式の一連のファイルを指定するにはワイルドカードの使用をお勧めします。 ただし、access_log_80 と access_log_443 のように複数の種類のファイルには使用しないでください。 複数の種類のファイルを指定するには、設定ファイルに別のストリームログのエントリを追加して、各種類のログファイルが異なるログストリームに行くようにします。 圧縮ファイルはサポートされていません。

例えば、以下のような設定がされているとして、この /var/log/messages がログローテートされて /var/log/messages-20200710 にローテートされるとします。

/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/default

    "logs": {
        "logs_collected": {
            "files": {
                "collect_list": [
                    {
                        "file_path": "/var/log/messages",
                        "log_group_name": "/var/log/messages.*",
                        "log_stream_name": "{local_hostname}"
                    }
                ]
            }
        }
    }

cloudwatchエージェントは最新の書き込みがあるログファイルを参照するので、/var/log/messages を参照して、ログ転送を継続しようとしますが、 ローテートされた古い方の /var/log/messages-20200710 にも書き込みがあると、InvalidSequenceTokenException が発生する

ローテートされた時点で、/var/log/messages と /var/log/messages-20200710 を別ファイルとして、認識しているからなのかも