CloudWatch Agentでワイルドカードを使用して可変名称のログをCloudWatch Logsへ転送してみた

こんにちは、坂巻です。

CloudWatch Agentを利用して、CloudWatch Logsへログを転送する際、取得対象ログが可変の名称の場合や、格納ディレクトリが可変の場合があるかと思います。

CodeDeployのスクリプトログは、まさにそういったケースかと思います。

/opt/codedeploy-agent/deployment-root/[deployment-group-ID]/[deployment-ID]/logs/scripts.log

上記のように、ディレクトリ名にデプロイID(deployment-ID)を含むため、CloudWatch Agent設定時にディレクトリ名は明らかになっていません。

CloudWatch Agent設定ファイルのlogsセクションでは、ワイルドカードが使用できますので、そういったケースに対応できるかと思います。

本エントリでは、ワイルドカードを使用してCloudWatch Logsへログを転送してみましたので、そのアウトプットになります。

前提

EC2の構築手順については割愛しますが、Amazon Linux 2(ami-0f9ae750e8274075b)を利用してEC2を作成しました。

01

EC2のロールには、以下のポリシーを付与しています。

  • CloudWatchLogsFullAccess
  • AmazonSSMFullAccess

CloudWatch Agentの利用は、SSM Agentのバージョン2.2.93.0以降が必要になります。

最新のAmazon Linux 2を利用していれれば、SSM Agentのバージョンは2.2.93.0以降かと思いますが、参考までにバージョンの確認方法を記載しておきます。

該当のインスタンスにて、以下のコマンドを実行することで確認可能です。

$ INSTANCE_ID=`curl http://169.254.169.254/latest/meta-data/instance-id`
$ aws ssm describe-instance-information --query InstanceInformationList[?InstanceId==\`${INSTANCE_ID}\`].AgentVersion --output text --region ap-northeast-1
2.3.372.0

マネジメントコンソールから確認する際は、Systems Managerコンソールの[インベントリ]から、確認可能です。

02

SSM Agentのバージョンが古い場合は、以下を参考にアップデートを実施してください。

環境構築

CloudWatch Agentインストール

ここでは、コマンドラインを使用してインストールを行いました。実行コマンド等については、以下ドキュメントをご確認ください。

インストールが済んでも、CloudWatch Agentはまだ起動していない状態です。

$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status
{
  "status": "stopped",
  "starttime": "",
  "version": "1.210825.0"
}

設定ファイル作成

Systems Managerパラメータストアに、CloudWatch Agentの設定ファイルを作成します。

03

パラメータの値は下記となります。

{
  "agent": {
    "metrics_collection_interval": 10,
    "logfile": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log"
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/home/ec2-user/*/*.log",
            "log_group_name": "script.log"
          }
        ]
      }
    }
  }
}

上記設定では/home/ec2-user配下、任意のディレクトリ配下すべての「.log」ファイルが収集されます。logsセクションの詳細については、以下をご確認ください。

CloudWatch Agent起動

CloudWatch Agentに設定を渡し起動します。 対象サーバにログインし、先程作成したパラメータ名を環境変数にセットします。

PRM_NAME=PARM
echo ${PRM_NAME}
PARM

以下コマンドでCloudWatch Agentを起動します。

$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a append-config -m ec2 -c ssm:${PRM_NAME} -s

(省略)

Redirecting to /bin/systemctl restart amazon-cloudwatch-agent.service

CloudWatch Agentの状態を確認します。

$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status
{
  "status": "running",
  "starttime": "2019-04-21T07:53:59+0000",
  "version": "1.210825.0"
}

以下コマンドで、サーバに適用された定義を確認することが可能です。

$ ls -l /etc/amazon/amazon-cloudwatch-agent/amazon-cloudwatch-agent.d/ssm_${PRM_NAME}
-rwxr-xr-x 1 root root 368 Apr 23 05:47 /etc/amazon/amazon-cloudwatch-agent/amazon-cloudwatch-agent.d/ssm_PARM
$ cat /etc/amazon/amazon-cloudwatch-agent/amazon-cloudwatch-agent.d/ssm_${PRM_NAME}
{
  "agent": {
    "metrics_collection_interval": 10,
    "logfile": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log"
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/home/ec2-user/*/*.log",
            "log_group_name": "script.log"
          }
        ]
      }
    }
  }
}[ec2-user@ip-172-31-45-232 ~]$

動作確認

現時点では、CloudWatch Logsに転送されたログは無いため、ロググループは存在していません。

$ aws logs describe-log-groups --region ap-northeast-1
{
    "logGroups": []
}

取得対象のログを作成するため/home/ec2-user/配下に任意のディレクトリを作成します。

DIR_NAME=strawberry
mkdir ${HOME}/${DIR_NAME}
$ ls -d ${HOME}/${DIR_NAME}
/home/ec2-user/strawberry

ログを出力します。

$ echo "Chocolate->script.log"  > ${HOME}/${DIR_NAME}/script.log
$ cat ${HOME}/${DIR_NAME}/script.log
Chocolate->script.log

上記ログ作成後にCloudWatch Logsを確認すると、ロググループが作成されています。

$ aws logs describe-log-groups --region ap-northeast-1
{
    "logGroups": [
        {
            "arn": "arn:aws:logs:ap-northeast-1:392138789764:log-group:script.log:*",
            "creationTime": 1555998921580,
            "metricFilterCount": 0,
            "logGroupName": "script.log",
            "storedBytes": 0
        }
    ]
}

転送されたログを確認します。 CloudWatch Agentの設定でログストリームを指定していないので、ログストリーム名はインスタンスIDが利用されます。

$ INSTANCE_ID=`curl http://169.254.169.254/latest/meta-data/instance-id`
$ echo ${INSTANCE_ID}
i-09de84c7b4f119694

想定どおり、CloudWatch Logsにログが転送されていました。

$ aws logs get-log-events --log-group-name script.log --log-stream-name ${INSTANCE_ID} --query 'events[]' --output text --region ap-northeast-1
1555998921874	Chocolate->script.log	1555998916472

更に別のログを作成し、動作を確認してみたいと思います。

$ echo "Almond->ope.log" >> ${HOME}/${DIR_NAME}/ope.log
$ cat ${HOME}/${DIR_NAME}/ope.log
Almond->ope.log

CloudWatch Agentの設定で、ロググループを分けていませんので、ロググループは追加されていません。

$ aws logs describe-log-groups --region ap-northeast-1
{
    "logGroups": [
        {
            "arn": "arn:aws:logs:ap-northeast-1:392138789764:log-group:script.log:*",
            "creationTime": 1555837369702,
            "metricFilterCount": 0,
            "logGroupName": "script.log",
            "storedBytes": 0
        }
    ]
}

追加したログもCloudWatch Logsに転送されていました。

$ aws logs get-log-events --log-group-name script.log --log-stream-name ${INSTANCE_ID} --query 'events[]' --output text --region ap-northeast-1
1555998921874	Chocolate->script.log	1555998916472
1556001976514	Almond->ope.log	1556001976471

ワイルドカードを使用して可変名称のログは取得できましたが、同一のロググループに保存されてしまいました。ログ種別が異なる場合は、別のロググループに保存すべきですので、CloudWatch Agentの設定を変更して、各種ログファイルが異なるロググループに転送されるよう設定したいと思います。こちらの環境をベースに確認していきますので、先ずはCloudWatch Agentを停止させます。

$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a stop
Redirecting to /bin/systemctl stop amazon-cloudwatch-agent.service
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status
{
  "status": "stopped",
  "starttime": "",
  "version": "1.210825.0"
}

先程作成したログを削除します。

$ ls -l ${HOME}/${DIR_NAME}
total 8
-rw-rw-r-- 1 ec2-user ec2-user 13 Apr 21 09:23 ope.log
-rw-rw-r-- 1 ec2-user ec2-user 16 Apr 21 09:21 script.log
$ rm ${HOME}/${DIR_NAME}/*.log
$ ls -l ${HOME}/${DIR_NAME}
total 0

CloudWatch Logsのロググループを削除します。

$ aws logs delete-log-group --log-group-name script.log --region ap-northeast-1
$ aws logs describe-log-groups --region ap-northeast-1
{
    "logGroups": []
}

パラメータストアに保存されたCloudWatch Agentの設定を更新します。ログロググループが異なるよう以下の設定とします。

{
  "agent": {
    "metrics_collection_interval": 10,
    "logfile": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log"
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/home/ec2-user/*/script.log",
            "log_group_name": "script.log"
          },
          {
            "file_path": "/home/ec2-user/*/ope.log",
            "log_group_name": "ope.log"
          }
        ]
      }
    }
  }
}

以下コマンドでCloudWatch Agentを起動します。

$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a append-config -m ec2 -c ssm:${PRM_NAME} -s

(省略)

Redirecting to /bin/systemctl restart amazon-cloudwatch-agent.service

CloudWatch Agentの状態を確認します。

$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status
{
  "status": "running",
  "starttime": "2019-04-23T06:55:15+0000",
  "version": "1.210825.0"
}

各種ログを出力します。

$ echo "Chocolate2->script.log" >> ${HOME}/${DIR_NAME}/script.log
$ echo "Almond2->ope.log" >> ${HOME}/${DIR_NAME}/ope.log
$ echo "Matcha->test.log" >> ${HOME}/${DIR_NAME}/test.log
$ ls -l ${HOME}/${DIR_NAME}
total 12
-rw-rw-r-- 1 ec2-user ec2-user 17 Apr 23 06:58 ope.log
-rw-rw-r-- 1 ec2-user ec2-user 23 Apr 23 06:58 script.log
-rw-rw-r-- 1 ec2-user ec2-user 17 Apr 23 06:58 test.log

CloudWatch Logsのロググループを確認すると、指定通り2つのロググループが作成されました。

$ aws logs describe-log-groups --region ap-northeast-1
{
    "logGroups": [
        {
            "arn": "arn:aws:logs:ap-northeast-1:392138789764:log-group:ope.log:*",
            "creationTime": 1556003696369,
            "metricFilterCount": 0,
            "logGroupName": "ope.log",
            "storedBytes": 0
        },
        {
            "arn": "arn:aws:logs:ap-northeast-1:392138789764:log-group:script.log:*",
            "creationTime": 1556003690420,
            "metricFilterCount": 0,
            "logGroupName": "script.log",
            "storedBytes": 0
        }
    ]
}

それぞれのロググループで、指定どおりログがCloudWatch Logsに転送されていました。

$ aws logs get-log-events --log-group-name script.log --log-stream-name ${INSTANCE_ID} --query 'events[]' --output text --region ap-northeast-1
1556003690701	Chocolate2->script.log	1556003685323
$ aws logs get-log-events --log-group-name ope.log --log-stream-name ${INSTANCE_ID} --query 'events[]' --output text --region ap-northeast-1
1556003696658	Almond2->ope.log	1556003691323

さいごに

CloudWatch Agentのみで、可変名称のログをCloudWatch Logsへ転送することができました。logsセクションにワイルドカードを使用することで、設定時にディレクトリ名が明らかになっていないログに対応できますね!