FireLens で収集するログのサイズに関する考慮
はじめに
大きなシステムでログ収集を行う場合、ログの流量(一定期間内に何件のログを処理しないといけないか)とログのサイズ(一件あたりのログがどの程度のサイズか)の考慮が必要です。これらが想定を大きく超えるとクラウド利用料が大きく膨らんだり、ログを集めきれずに欠損してしまうような状況が起こります。
今回は FireLens を使用して CloudWatch Logs にログを送信する場合のサイズ上限と、超過した場合の挙動を検証したので記録しておきます。
FireLens のサイズ上限
FireLens というよりはコンテナロガーの仕様のようですが、ソケット経由で Fluent Bit が受け取るログは 16kb に制限されます。16kb を超過したログは分割されて受信します。
検証してみましょう。
以下のようなコンテナを ECS 上で実行します。そうすると毎秒「16,384 文字の0
+ TEST
」を Stdout に出力するので、そのログを使用して挙動を見てみます。
FROM amazonlinux:2
COPY entrypoint.sh /tmp
ENTRYPOINT ["/tmp/entrypoint.sh"]
#!bin/sh
while true; do sleep 1; printf "%016384dTEST\n"; done
partial_message
、partial_id
、partial_ordinal
、partial_last
の 4 つのキーがログに付与され、ログが分割されたことがわかります。
{
"partial_message": "true",
"partial_id": "7bc16f7a1b57f693f141742c44a086074a4a3d377e345d222b83fe1b24e3deb5",
"partial_ordinal": "1",
"partial_last": "false",
"ecs_cluster": "example-ecs",
"ecs_task_arn": "arn:aws:ecs:ap-northeast-1:account-id:task/example-ecs/ea92eef62d4c4d63a94cf249bcc66ea2",
"ecs_task_definition": "example-taskdef:1",
"container_id": "ea92eef62d4c4d63a94cf249bcc66ea2-3935363592",
"container_name": "main",
"source": "stdout",
"log": "00000000...00000000"
}
{
"partial_message": "true",
"partial_id": "7bc16f7a1b57f693f141742c44a086074a4a3d377e345d222b83fe1b24e3deb5",
"partial_ordinal": "2",
"partial_last": "true",
"ecs_cluster": "example-ecs",
"ecs_task_arn": "arn:aws:ecs:ap-northeast-1:account-id:task/example-ecs/ea92eef62d4c4d63a94cf249bcc66ea2",
"ecs_task_definition": "example-taskdef:1",
"container_id": "ea92eef62d4c4d63a94cf249bcc66ea2-3935363592",
"container_name": "main",
"source": "stdout",
"log": "TEST"
}
Fluent Bit が分割されたログを受け取った場合は、Multiline Parser を使用して結合することができます。
Multiline Parser については以下の記事でも紹介しています。詳細はそちらを確認ください。
以下の組み込みパーサーを使用するだけです。
{
"ecs_cluster": "example-ecs",
"ecs_task_arn": "arn:aws:ecs:ap-northeast-1:account-id:task/example-ecs/c205787da5204f0e98c7958299a35a34",
"ecs_task_definition": "example-taskdef:1",
"container_id": "c205787da5204f0e98c7958299a35a34-3935363592",
"container_name": "main",
"source": "stdout",
"log": "00000000...00000000TEST"
}
CloudWatch Logs のサイズ上限
CloudWatch Logs のログイベントサイズ上限は 256kb です。これはハードリミットのため上限緩和できません。
Multiline Parser を使用して FireLens の 16kb 制限を回避すると、今度はこちらの制限に引っかかる場合があります。
こちらも検証してみました。
先ほど使用したコンテナの定義を少し変更して、今度は毎秒「262,144 文字の0
+ TEST
」を Stdout に出力させます。
#!bin/sh
while true; do sleep 1; printf "%0262144dTEST\n"; done
CloudWatch Logs には以下のように後半部分が欠損したログが収集されました。これにより Json フォーマットも壊れてしまっています。
{
"ecs_cluster":"example-ecs",
"ecs_task_arn":"arn:aws:ecs:ap-northeast-1:account-id:task/example-ecs/973e05dc9c6b498b9450da1ac5f246a1",
"ecs_task_definition":"example-taskdef:5",
"container_id":"973e05dc9c6b498b9450da1ac5f246a1-3935363592",
"container_name":"main",
"source":"stdout",
"log":"00000000...00000000
CloudWatch Logs のサイズ上限によりログが尻切れになると、FireLens 側のログに以下のようなイベントが出力されます。
[2024/01/08 02:17:15] [ warn] [output:cloudwatch_logs:cloudwatch_logs.1] [size=262466] Truncating event which is larger than max size allowed by CloudWatch
検知したところですでにログは失われてしまっているのでどうしようもないですが、ログ欠損が発生したときの原因調査には使えそうです。
おわりに
ログがここまで大きなサイズになることはあまりないかもしれませんが、スタックトレースをログ出力しているようなケースでは注意が必要です。いざトラブルが発生したとき、原因調査をしようと思ったらログが欠損していて調査ができない…みたいなことにならないように、ログサイズに関する制限事項はあらかじめ整理しておきましょう!
今回は以上です👋
Discussion