fluentdでCloudWatch Logsのログを収集(fluent-plugin-cloudwatch-logs)

fluent-plugin-cloudwatch-logsin_cloudwatch_logsでCloudWatch Logsからログを収集してみたので手順をまとめます。

github.com

環境

$ lsb_release -d
Description:    Ubuntu 22.04 LTS
$ td-agent --version
td-agent 4.4.1 fluentd 1.15.2 (c32842297ed2c306f1b841a8f6e55bdd0f1cb27f)
$ td-agent-gem list fluent-plugin-cloudwatch-logs
fluent-plugin-cloudwatch-logs (0.14.3)

td-agentのインストール

Install by DEB Package (Debian/Ubuntu)の手順に従い、 td-agent をインストールします。

# For Ubuntu Jammy
# td-agent 4 (experimental)
$ curl -fsSL https://toolbelt.treasuredata.com/sh/install-ubuntu-jammy-td-agent4.sh | sh

デーモンの起動を確認します。

$ systemctl status td-agent
● td-agent.service - td-agent: Fluentd based data collector for Treasure Data
     Loaded: loaded (/lib/systemd/system/td-agent.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2022-08-30 18:09:38 JST; 1min 19s ago
       Docs: https://docs.treasuredata.com/display/public/PD/About+Treasure+Data%27s+Server-Side+Agent
   Main PID: 1608 (fluentd)
      Tasks: 9 (limit: 4692)
     Memory: 100.1M
        CPU: 1.765s
     CGroup: /system.slice/td-agent.service
             ├─1608 /opt/td-agent/bin/ruby /opt/td-agent/bin/fluentd --log /var/log/td-agent/td-agent.log --daemon /var/run/td-agent/td>
             └─1611 /opt/td-agent/bin/ruby -Eascii-8bit:ascii-8bit /opt/td-agent/bin/fluentd --log /var/log/td-agent/td-agent.log --dae>

Aug 30 18:09:38 ip-172-31-31-91 systemd[1]: Starting td-agent: Fluentd based data collector for Treasure Data...
Aug 30 18:09:38 ip-172-31-31-91 systemd[1]: Started td-agent: Fluentd based data collector for Treasure Data.

標準設定で有効なHTTPエンドポイントにサンプルログを投げ、動作確認を行います。

$ curl -X POST -d 'json={"json":"message"}' http://localhost:8888/debug.test
$ tail -n 1 /var/log/td-agent/td-agent.log
2022-08-30 18:12:07.867864796 +0900 debug.test: {"json":"message"}

fluent-plugin-cloudwatch-logsのインストール

fluent-plugin-cloudwatch-logsをインストールします。

$ sudo td-agent-gem install fluent-plugin-cloudwatch-logs
Fetching fluent-plugin-cloudwatch-logs-0.14.3.gem
Fetching aws-sdk-cloudwatchlogs-1.53.0.gem
Successfully installed aws-sdk-cloudwatchlogs-1.53.0
Successfully installed fluent-plugin-cloudwatch-logs-0.14.3
Parsing documentation for aws-sdk-cloudwatchlogs-1.53.0
Installing ri documentation for aws-sdk-cloudwatchlogs-1.53.0
Parsing documentation for fluent-plugin-cloudwatch-logs-0.14.3
Installing ri documentation for fluent-plugin-cloudwatch-logs-0.14.3
Done installing documentation for aws-sdk-cloudwatchlogs, fluent-plugin-cloudwatch-logs after 0 seconds
2 gems installed

IAMユーザ(またはロール)の作成

ログの取得( in_cloudwatch_logs )に必要な以下のポリシーを割り当てたIAMユーザまたはロールを作成します。
IAMロールを使用する場合はEC2インスタンスに割り当ててください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:GetLogEvents",
                "logs:DescribeLogStreams"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

fluentdの設定

ロググループ /aws/log/group 以下の複数のログストリーム app-* を対象にログを取得する例です。
取得したログは標準出力に吐き出して確認します。

<source>
  @type cloudwatch_logs
  tag cloudwatch
  aws_key_id ...  # IAMユーザのアクセスキー(IAMロールの場合は不要)
  aws_sec_key ...  # IAMユーザのシークレットアクセスキー(IAMロールの場合は不要)
  region ap-northeast-1  # 東京リージョンの場合
  log_group_name /aws/log/group  # ロググループ名
  use_log_stream_name_prefix true  # log_stream_nameを接頭辞として使用
  log_stream_name app-  # ログストリームの接頭辞を指定
  fetch_interval 60  # 1分毎にログを取得
  throttling_retry_seconds 30  # レート制限を超過した場合に30秒スリープ
  json_handler json
  <storage>  # 現在の状態(例:next_forward_token)を保存するファイルの指定
    @type local
    path /var/tmp/state.json
  </storage>
</source>
<match cloudwatch>
  @type stdout
</match>

td-agent.log にCloudWatch Logsのログが書き込まれることを確認できました。
以下はEKSのContainer Insightsから取得したApacheコンテナのログです。

...
2022-08-31 14:21:47.000000000 +0900 cloudwatch: {"log":"httpd-combined 192.168.35.125 - - [31/Aug/2022:05:21:47 +0000] \"GET ...
2022-08-31 14:21:51.000000000 +0900 cloudwatch: {"log":"httpd-combined 192.168.35.125 - - [31/Aug/2022:05:21:47 +0000] \"POST ...

注意事項

対象となるログストリームが多いとAPI DescribeLogStreams のレート制限(デフォルト:5件/秒)を超過し、 ThrottlingException が発生する恐れがあります。

#0 thread exited by unexpected error plugin=Fluent::Plugin::CloudwatchLogsInput title=:in_cloudwatch_logs_runner error_class=Aws::CloudWatchLogs::Errors::ThrottlingException error="Rate exceeded"

このような場合にはクォータの引き上げを要求するか、 log_stream_name の設定で十分に対象を絞る必要があります。