コスト削減や長期保管のために、CloudWatch LogsからS3へのログ退避は一般的な手法だと思います。
私も以前、「CloudWatch Logsのログを1ヶ月後にS3へ自動転送する」という要件に対し、EventBridgeからのCreate exportを利用して実装を試みました。しかし設定に問題はないはずが、なぜかログがS3に転送されないという問題に直面しました。
結論から言ってしまうとCloudWatch Logsのとあるクォータが原因でした。
本記事では、その際に遭遇した問題の詳細、原因の特定、そして最終的な解決策についてご紹介したいと思います。同じような問題に遭遇した方の助けになれば幸いです。
前提
- 複数のロググループからアーカイブ用のS3にログを転送する
- 転送頻度は毎月1日の0:00
- トリガーはEventBridge スケジューラー
経緯について
前提に記載の通り転送対象のCloudWatch Logsは複数あり、毎月1日の0:00にEventBridgeスケジュールが起動します。EventBridgeスケジュールはロググループの数に応じて作成していました。毎月1日の0:00に複数のEventBridgeスケジューラーが同時に起動する形になります。
しかし、日付が変わってもS3にはログが出力されていません。正確に言うと、複数のロググループのうち、たった1つのロググループのログしかS3に転送されていませんでした。
「・・・どうゆう状況?」と頭に疑問符が浮かびました。
何が問題だったのか
EventBridgeスケジューラーの設定は、転送元と転送先の設定が異なるだけで、その他の設定は全て同じです。原因の見当がつかなかったためCloudTrailのログを確認してみると、以下のエラーが出力されていました。
"errorCode": "LimitExceededException"
"errorMessage": "Resource limit exceeded."
何やら制限に引っ掛かっている模様・・・
さらに調査を進めた結果、以下のAWS公式ドキュメントに辿り着きました。
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/cloudwatch_limits_cwl.html
CloudWatch Logsのexport taskにはクォータが存在していました。ドキュメントには以下のように記載されています。
アカウントごとに、一度に 1 つのアクティブ (実行中または保留中) のエクスポートタスクがあります。このクォータは変更できません。
この記述から、アカウント単位で同時に実行できるexport taskは1つのみであり、複数のexport taskを同時に実行することは不可能だったということが判明しました。
結果として、各EventBridgeスケジューラーの起動時間を数分ずつずらすことで、全てのexport taskが順番に実行され、無事に全てのログがS3に出力されるようになりました。
まとめ
CloudWatch Logsのexport taskには、「アカウントごとに一度に1つのアクティブなエクスポートタスク」という変更不可能なクォータが存在します。そのため、複数のロググループからS3にログを転送する際には、EventBridgeスケジューラーなどのトリガーを用いて、export taskの実行時間を意図的にずらしてあげる必要があるというのが今回の教訓でした。もし同様の構成を組む際には、この点に注意していただければと思います。