🚀

FireLens(Fluent Bit v2.1) で Tomcat(SpringBoot) からのログを処理する

2024/02/11に公開

ECSを試しているついでにFireLensでのログ収集基盤構築までやってみたのでその記録です。
アプリケーション自体はSpringBootで作っており、デフォルトのTomcatをwebサーバーとしています。

やりたいこと

  • エラーログを分ける
  • /helthcheckへのアクセスログは無視する
  • アクセスログはS3とCloudWatchの2つに流す

最終的にCloudWatchに出力するストリームは以下画像のようになりました。

1.FireLensから出力されるログを整形する

Firelensからは以下のような形式でログが返される。
条件判定に使いたいのは、logに含まれる内容である。

{
    "container_id": "",
    "container_name": "",
    "ecs_cluster": "",
    "ecs_task_arn": "",
    "ecs_task_definition": "",
    "log": "0.0.0.000 - - [10/Feb/2024:00:00:00 +0000] \"GET /helthcheck HTTP/1.1\" 200 2",
    "source": "stdout"
}

Fluent BitのStream ProcessorのSQLで処理できるようにするにはとりあえずJSON形式にする必要がある。

今回は以下Githubにあるサンプルをそのまま使い、Parserにて事前処理する。

parser.conf

[PARSER]
    Name   apache #ただの名前 
    Format regex
    Regex  ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
    Time_Key time
    Time_Format %d/%b/%Y:%H:%M:%S %z

すると以下のようなJSONに整形される

{
    "code": "200",
    "container_id": "",
    "container_name": "",
    "ecs_cluster": "",
    "ecs_task_arn": "",
    "ecs_task_definition": "",
    "host": "0.0.0.000",
    "method": "GET",
    "path": "/helthcheck",
    "size": "",
    "source": "stdout",
    "user": "-"
}

2.Stream Processorで処理する

上記JSON形式に整理できればあとは、SQLで処理できる。

  • FireLensから出力されるイベントorレコードは、<コンテナ名>-firelens-<コンテナID>というタグが付けられている。このタグがついているものだけ処理するように絞り込む。
  • 1つ目は、/helthcheckだけ除外するクエリ
  • 2つ目は、エラーコードのものだけ、error-logタグのついたStreamとして再生成するクエリ

stream_processor.conf

[STREAM_TASK]
    Name access
    Exec CREATE STREAM access WITH (tag='access-log') AS SELECT * FROM TAG:'*-firelens-*' WHERE path <> '/helthcheck';

[STREAM_TASK]
    Name error
    Exec CREATE STREAM error WITH (tag='error-log') AS SELECT * FROM TAG:'*-firelens-*' WHERE code >= 400 AND code < 600;

3.メインの.confを作成

1.と2.で作成したファイルを両方読み込んでいる。
処理の順番としては以下になる。

  1. FILTERでparser.confで設定したapatch parser(ただの名前)によってログを整形
  2. stream_processor.confにて、access-logとerror-logタグを持つストリームを作成
  3. 再度、access-logとerror-logストリームはINPUT->OUTPUTまで流される
  4. [OUTPUT]によって出力

fluent-bit-custom.conf

[SERVICE]
    Parsers_File /fluent-bit/parser.conf
    Streams_File /fluent-bit/stream_processor.conf

[FILTER]
    Name parser
    Match *
    Key_Name log
    Parser apache
    Reserve_Data True

[OUTPUT]
    Name cloudwatch
    Match access-log
    region ${AWS_REGION}
    log_group_name ${LOG_GROUP_NAME}
    log_stream_prefix from-fluentbit/
    auto_create_group true

[OUTPUT]
    Name cloudwatch
    Match error-log
    region ${AWS_REGION}
    log_group_name ${LOG_GROUP_NAME}
    log_stream_prefix from-fluentbit/
    auto_create_group true
    
[OUTPUT]
    Name s3
    Match access-log
    region ${AWS_REGION}
    bucket ${LOG_BUCKET_NAME}
    total_file_size 1M
    upload_timeout 1m

FireLensの挙動について

FireLensを使うと、標準出力へのログはFluentd Docker ログドライバーを介して Unix ソケット経由で FireLens コンテナに送信される。

Fluentd Docker ログドライバーについて

  • 実は、container_id,container_name,sourceについてはこのログドライバーによって付与されており、ログがlogをキーにして格納されるのもこのドライバーが行なっている。
  • このドライバーはTCP,unixドメインsocket通信の2つをサポートしている。
    • fluentdhost:24224 or unix:///path/to/fluentd.sock

参照記事

以下AWSの記事が最も参考になった。
https://aws.amazon.com/jp/blogs/news/splitting-application-logs-multiple-streams-fluent/

Discussion