AWS FireLens (AWS for Fluent Bit) で16KB以上のログを扱ってみた

AWS FireLens (AWS for Fluent Bit) で16KB以上のログを扱ってみた

サイズが大きいログを出力する場合はFluent Bitの設定に気をつけよう
2026.01.18

16KB以上のログを分割せずに扱いたい

こんにちは、のんピ(@non____97)です。

皆さんはFluent Bitで16KB以上のログを分割せずに扱いたいなと思ったことはありますか? 私はあります。

以下Fluent Bit公式マニュアルで紹介されているとおり、Fluent Bitでは16KB以上のログは分割されてしまいます。

When Fluent Bit is consuming logs from a container runtime, such as Docker, these logs will be split when larger than a certain limit, usually 16&nbspKB. If your application emits a 100K log line, it will be split into seven partial messages. The docker parser will merge these back to one line. If instead you are using the Fluentd Docker Log Driver to send the logs to Fluent Bit, they might look like this:

{"source": "stdout", "log": "... omitted for brevity...", "partial_message": "true", "partial_id": "dc37eb08b4242c41757d4cd995d983d1cdda4589193755a22fcf47a638317da0", "partial_ordinal": "1", "partial_last": "false", "container_id": "a96998303938eab6087a7f8487ca40350f2c252559bc6047569a0b11b936f0f2", "container_name": "/hopeful_taussig"}]

Multiline | Fluent Bit: Official Manual

分割されてしまうとログ分析をするときに正しくクエリできず、困ってしまいます。

対応としては以下のようにモードがpartial_messageのMultiLineフィルターを使用する必要があります。

[FILTER]
  name                  multiline
  match                 *
  multiline.key_content log
  mode                  partial_message

インターネット上で公開されている情報で、AWS for Fluent Bitにおいてpartial_messageのMultiLineフィルター使用前後のログの状態を確認しているものを見つけられなかったので、実際に試してみます。

やってみた

検証環境

検証環境は以下のとおりです。

検証環境構成図.png

以下記事で使用したものを流用します。

https://dev.classmethod.jp/articles/aws-firelens-to-s3-with-data-firehose-dynamic-partitioning/

コードは以下リポジトリに保存しています。

https://github.com/non-97/ecs-native-blue-green/tree/v1.0.1

partial_messageのMultiLineフィルター使用前

まずは、partial_messageのMultiLineフィルター使用前です。

/app/large-log/にアクセスすると、20,000文字のXが記録されたログを出力するパスを用意しました。

./src/container/app/src/index.ts
app.get("/large-log", (req: Request, res: Response) => {
  // 16KB を超える大きなログを生成
  // FluentBitの16KB制限をテストするため
  const largeData = {
    message: "Testing 16KB+ log handling",
    timestamp: new Date().toISOString(),
    data: "X".repeat(20000),
  };

  req.log.error(largeData, "Large log entry generated");

  res.status(200).json({
    message: "Large log generated successfully",
    logSize: JSON.stringify(largeData).length,
    timestamp: new Date().toISOString(),
  });
});

こちらにアクセスします。

> curl http://EcsNat-AlbCo-gB01lRgFgX9v-1376474775.us-east-1.elb.amazonaws.com/app/large-log/
{"error":"Large log generated successfully","logSize":20089,"timestamp":"2026-01-17T08:17:23.126Z"}%

CloudWatch Logsを確認すると、確かにログが2つに分割されていることを確認できました。

1.長大なログ.png

S3バケットに出力されたログも2行に分割されてしまっています。

1.長大なログのオブジェクト.png

よくよくログを見ると、logが途中で分割されてしまっている影響か、JSONでパースされず、文字列として扱われてしまっています。

{
    "partial_ordinal": "1",
    "partial_last": "false",
    "container_id": "16e9de31cf944b9f86e68b2f3f8a36d4-0527074092",
    "container_name": "app",
    "source": "stderr",
    "log": "{\"level\":\"error\",\"time\":\"2026-01-17T08:27:27.388Z\",\"pid\":50,\"hostname\":\"ip-10-10-10-102.ec2.internal\",\"req\":{\"id\":16,\"method\":\"GET\",\"url\":\"/large-log/\",\"query\":{},\"params\":{},\"headers\":{\"host\":\"ecsnat-albco-gb01lrgfgx9v-1376474775.us-east-1.elb.amazonaws.com\",\"x-real-ip\":\"10.10.10.11\",\"x-forwarded-for\":\"<送信元IPアドレス> 10.10.10.11\",\"x-forwarded-proto\":\"http\",\"connection\":\"close\",\"x-forwarded-port\":\"80\",\"x-amzn-trace-id\":\"Root=1-696b47ef-5967e86740233a79392a7665\",\"accept\":\"*/*\",\"user-agent\":\"curl/8.7.1\"},\"remoteAddress\":\"127.0.0.1\",\"remotePort\":42364},\"message\":\"Testing 16KB+ log handling\",\"timestamp\":\"2026-01-17T08:27:27.388Z\",\"data\":\"XXXXX..(中略)..XXXXXX",
    "partial_message": "true",
    "partial_id": "56571121fe67f58e10e882d7812d3e9de3e7c22145bb37ce793f4b06bce2878c",
    "ecs_cluster": "EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-0UD5SYuupUOg",
    "ecs_task_arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-0UD5SYuupUOg/16e9de31cf944b9f86e68b2f3f8a36d4",
    "ecs_task_definition": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2:47"
}
{
    "partial_last": "true",
    "container_id": "16e9de31cf944b9f86e68b2f3f8a36d4-0527074092",
    "container_name": "app",
    "source": "stderr",
    "log": "XXXX..(中略)..XXX\",\"msg\":\"Large log entry generated\"}",
    "partial_message": "true",
    "partial_id": "56571121fe67f58e10e882d7812d3e9de3e7c22145bb37ce793f4b06bce2878c",
    "partial_ordinal": "2",
    "ecs_cluster": "EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-0UD5SYuupUOg",
    "ecs_task_arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-0UD5SYuupUOg/16e9de31cf944b9f86e68b2f3f8a36d4",
    "ecs_task_definition": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2:47"
}

CloudWatch Logs Insightsでログ検索をするときにこれでは不便です。

partial_messageのMultiLineフィルター使用後

それではpartial_messageのMultiLineフィルター使用後の様子を確認します。

Fluent Bitの設定ファイルは以下のようにしました。

./src/fluentbit-config/extra.conf
# ref : 詳解 FireLens – Amazon ECS タスクで高度なログルーティングを実現する機能を深く知る | Amazon Web Services ブログ https://aws.amazon.com/jp/blogs/news/under-the-hood-firelens-for-amazon-ecs-tasks/
# ref : aws-for-fluent-bit/use_cases/init-process-for-fluent-bit/README.md at mainline · aws/aws-for-fluent-bit https://github.com/aws/aws-for-fluent-bit/blob/mainline/use_cases/init-process-for-fluent-bit/README.md
[SERVICE]
    Flush                 1
    Grace                 30
    Parsers_File          /fluent-bit/parsers/parsers.conf

# 16KB制限により分割されたログレコードを再結合
# partial_message モードで元の1つのログレコードに再結合
# ref : Multiline | Fluent Bit: Official Manual https://docs.fluentbit.io/manual/data-pipeline/filters/multiline-stacktrace
[FILTER]
    Name                  multiline
    Match                 *-firelens-*
    multiline.key_content log
    mode                  partial_message
    flush_ms              2000

# appコンテナのログにマルチラインパーサーを適用
# Loggerとしてpinoを使用して構造化ログとして出力させているため、今回は効果を発揮しない
# ref : Multiline parsing | Fluent Bit: Official Manual https://docs.fluentbit.io/manual/data-pipeline/parsers/multiline-parsing
# ref : 複数行またはスタックトレースの Amazon ECS ログメッセージの連結 - Amazon Elastic Container Service https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/firelens-concatanate-multiline.html
[FILTER]
    Name                  multiline
    Match                 app-firelens*
    multiline.key_content log
    multiline.parser      nodejs_stacktrace

# appコンテナのログをJSONとしてパース
# タイムスタンプはISO 8601形式でそのまま保持(json_without_timeパーサーを使用)
# そのままデフォルトのパーサーを使用すると、以下のようにパースに失敗する
#  [2026/01/13 01:47:55.17286147] [error] [parser] cannot parse '2026-01-13T01:47:53.124Z'
#  [2026/01/13 01:47:55.17313453] [ warn] [parser:json] invalid time format %d/%b/%Y:%H:%M:%S %z for '2026-01-13T01:47:53.124Z'
# ref : JSON format | Fluent Bit: Official Manual https://docs.fluentbit.io/manual/data-pipeline/parsers/json
[FILTER]
    Name                  parser
    Match                 app-firelens-*
    Key_Name              log
    Parser                json_without_time
    Reserve_Data          On

# webコンテナのログをパース
# Nginxを使用しているためNginxのパーサーを使用して、構造化ログに
[FILTER]
    Name                  parser
    Match                 web-firelens-*
    Key_Name              log
    Parser                nginx
    Reserve_Data          On

# webコンテナのログからELBヘルスチェック時のログ除外
# User agentで判定
[FILTER]
    Name                  grep
    Match                 web-firelens-*
    Exclude               agent ELB-HealthChecker/2\.0

# エラーログにタグを付与
# ステータスコードが5xxまたはstderrのログに付与
# マルチラインパーサーの無限ループ防止のため、すでに5xxまたはstderrのタグが付いているタグを除外
[FILTER]
    Name                  rewrite_tag
    Match_Regex           ^(?!5xx\.)(?!stderr\.).*-firelens-.*
    Rule                  $code ^5\d{2}$ 5xx.$TAG false
    Rule                  $source ^stderr$ stderr.$TAG false
    Emitter_Name          re_emitted

# 全てのログをFirehoseへ出力
# Data Firehose側での動的パーティショニングを行うため圧縮はしない
# Data Firehose側で解凍処理も可能だが、追加料金がかかる and データソースがCloudWatch Logsのみ
# ref : Amazon Kinesis Data Firehose | Fluent Bit: Official Manual https://docs.fluentbit.io/manual/data-pipeline/outputs/firehose
# ref : CloudWatch Logs を解凍する - Amazon Data Firehose https://docs.aws.amazon.com/ja_jp/firehose/latest/dev/writing-with-cloudwatch-logs-decompression.html
[OUTPUT]
    Name                  kinesis_firehose
    Match                 *-firelens-*
    delivery_stream       ${FIREHOSE_DELIVERY_STREAM_NAME}
    region                ${AWS_REGION}
    time_key              datetime
    time_key_format       %Y-%m-%dT%H:%M:%S.%3NZ

# 先頭が 5xx もしくは stderr のタグが付与されているログのみCloudWatch Logsへ出力
# ref : Amazon CloudWatch | Fluent Bit: Official Manual https://docs.fluentbit.io/manual/data-pipeline/outputs/cloudwatch
[OUTPUT]
    Name                  cloudwatch_logs
    Match_Regex           ^(5xx\.|stderr\.).*
    region                ${AWS_REGION}
    log_group_name        ${LOG_GROUP_NAME}
    log_stream_prefix     error/

S3バケットに設定ファイルをアップロードして、タスクを停止することで入れ替えます。

その後再度長大なログを出力させます。

> curl http://EcsNat-AlbCo-gB01lRgFgX9v-1376474775.us-east-1.elb.amazonaws.com/app/large-log/
{"message":"Large log generated successfully","logSize":20089,"timestamp":"2026-01-17T08:41:25.539Z"}%

すると、今度はログが途中で分割されず、一まとめにされていることを確認できました。

2.partial_message.png

S3バケットに出力されたログも同様です。(2回アクセスしたので2行出力されてしまっています)

2.partial_messageのオブジェクト.png

ログの内容を確認すると、以下のようにlogが正しくJSONでパースされていました。

{
    "level": "error",
    "time": "2026-01-17T08:41:25.536Z",
    "pid": 51,
    "hostname": "ip-10-10-10-72.ec2.internal",
    "req": {
        "id": 7,
        "method": "GET",
        "url": "/large-log/",
        "query": {},
        "params": {},
        "headers": {
            "host": "ecsnat-albco-gb01lrgfgx9v-1376474775.us-east-1.elb.amazonaws.com",
            "x-real-ip": "10.10.10.11",
            "x-forwarded-for": "<送信元IPアドレス> 10.10.10.11",
            "x-forwarded-proto": "http",
            "connection": "close",
            "x-forwarded-port": "80",
            "x-amzn-trace-id": "Root=1-696b4b35-64996db075d1717b53df48e4",
            "accept": "*/*",
            "user-agent": "curl/8.7.1"
        },
        "remoteAddress": "127.0.0.1",
        "remotePort": 50042
    },
    "message": "Testing 16KB+ log handling",
    "timestamp": "2026-01-17T08:41:25.536Z",
    "data": "XXXXX..(中略)..XXXXX",
    "msg": "Large log entry generated",
    "container_id": "4e8d9e60ba3a410cbe0d8901b14811d8-0527074092",
    "container_name": "app",
    "source": "stderr",
    "ecs_cluster": "EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-0UD5SYuupUOg",
    "ecs_task_arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-0UD5SYuupUOg/4e8d9e60ba3a410cbe0d8901b14811d8",
    "ecs_task_definition": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2:47"
}

ちなみに16KBのログを扱っているからといってFluent BitコンテナのCPUやメモリなどの各種メトリクスが明らかに跳ねているというのは確認できませんでした。

3.Container Insights.png

サイズが大きいログを出力する場合はFluent Bitの設定に気をつけよう

AWS FireLens (AWS for Fluent Bit) で16KB以上のログを扱ってみました。

サイズが大きいログを出力する場合はFluent Bitの設定に気をつけましょう。

なお、CloudWatch Logsのログイベントサイズの上限は1MBです。1MBのログはなかなか出力しないと思いますが認識はしておきましょう。

https://dev.classmethod.jp/articles/amazon-cloudwatch-logs-increases-log-event-size-1-mb/

https://dev.classmethod.jp/articles/firelens/

The batch of events must satisfy the following constraints:

  • The maximum batch size is 1,048,576 bytes. This size is calculated as the sum of all event messages in UTF-8, plus 26 bytes for each log event.
  • Events more than 2 hours in the future are rejected while processing remaining valid events.
  • Events older than 14 days or preceding the log group's retention period are rejected while processing remaining valid events.
  • The log events in the batch must be in chronological order by their timestamp. The timestamp is the time that the event occurred, expressed as the number of milliseconds after Jan 1, 1970 00:00:00 UTC. (In AWS Tools for PowerShell and the AWS SDK for .NET, the timestamp is specified in .NET format: yyyy-mm-ddThh:mm:ss. For example, 2017-09-15T13:45:30.)
  • A batch of log events in a single request must be in a chronological order. Otherwise, the operation fails.
  • Each log event can be no larger than 1 MB.
  • The maximum number of log events in a batch is 10,000.
  • For valid events (within 14 days in the past to 2 hours in future), the time span in a single batch cannot exceed 24 hours. Otherwise, the operation fails.

PutLogEvents - Amazon CloudWatch Logs

Fluent Bit側でも送信ログバッファサイズとCloudWatch Logsの1MB制限を比較して判定をしてくれます。今回の検証ではFlush1で設定しているため1秒ごとにログ出力をしようとします。

https://github.com/fluent/fluent-bit/blob/master/plugins/out_cloudwatch_logs/cloudwatch_api.h#L23-L30

https://github.com/fluent/fluent-bit/blob/master/plugins/out_cloudwatch_logs/cloudwatch_api.c#L828-L924

また、Data Firehoseにログを流す際に意識する必要があると思われるクォータは以下のとおりです。

名前 デフォルト 引き上げ可能 説明
動的パーティション サポートされている各リージョン: 500 不可 現在のリージョンにおける配信ストリームの動的パーティションの最大数。
Put リクエストのレート us-east-1: 2,000

us-west-2: 2,000

eu-west-1: 2,000

他のサポートされている各リージョン: 1,000
不可 現在のリージョンにおいて配信ストリームで実行できる 1 秒あたりの PutRecord リクエストと PutRecordBatch リクエストの合計最大数。
データのレート us-east-1: 5

us-west-2: 5

eu-west-1: 5

他のサポートされている各リージョン: 1
不可 現在のリージョンにおける配信ストリームの最大容量 (1 秒あたりのメビバイト数)。
レコードのレート us-east-1: 500,000

us-west-2: 500,000

eu-west-1: 500,000

他のサポートされている各リージョン: 100,000
不可 現在のリージョンにおける配信ストリームの最大容量 (1 秒あたりのレコード数)。

抜粋 : Amazon Data Firehose エンドポイントとクォータ - AWS 全般のリファレンス

この記事が誰かの助けになれば幸いです。

以上、クラウド事業本部 コンサルティング部の のんピ(@non____97)でした!

この記事をシェアする

FacebookHatena blogX

関連記事