先日、お仕事で久しぶりに、AWSのEC2に CloudWatch Agent
を入れる作業をしていたところ、ちょっとハマったポイントがあったのでここにメモしておきます。
目指す状態
- CloudWatch Agent が起動して、メトリクスを CloudWatch に送信している状態
- CloudWatch Agent が起動して、Webアプリケーションのログを CloudWatch Logs に送信している状態
- 本当はNginxとかOSの一部機能のログとかも送るけど、本メモの主題とは離れてるので、この観点での情報は割愛
IAM Role の設定
対象の EC2 Instance に設定する IAM Role には、以下の2つの AWS managed policy を付与しました。
AmazonSSMManagedEC2InstanceDefaultPolicy
: Session Manager で接続するために必要です。AmazonSSMManagedInstanceCore
でも良いと思います。これら2つの違いは SSM のパラメータストアを使うかどうかです。AmazonSSMManagedInstanceCore
だとssm:GetParameter
権限も付いてます。CloudWatchAgentServerPolicy
: CloudWatch にメトリクスを送ったり、CloudWatch Logs にログを送ったりする権限です。
CloudWatch Agent のインストール
https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-on-EC2-Instance.html
インストール手順の、公式のマニュアルは↑の通りです。command line から入れるか、Systems Manager から入れるか、CloudFormation でゴニョゴニョするか、の3択ですが、本メモではcommand line から実施しました。つまり、マニュアルとしては https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/installing-cloudwatch-agent-commandline.html を参照したということになります。
なお、このマニュアルには、1つだけ、とても不親切な点があります。それは、インストール手順の最後にAgentを起動する際、設定ファイルのファイルパスの入力を求めているのですが、マニュアルをそこまで *順番通りに* 読んでいると、設定ファイルを書く工程に到達しないという点です(または私が見落としたか)。
設定ファイルの書き方やデフォルトのファイルパスは https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/create-cloudwatch-agent-configuration-file.html にあります。
設定ファイルの作成
前述のマニュアルにある通り、設定ファイルはデフォルトではJSON形式です。おそらく他のフォーマットも読んでくれるのでしょうけども、設定ファイルを作ってくれるwizardさんがJSONを吐くので、JSONを使うのが一般的なのだろうと思います。私もJSON派です。
wizardさんは、マニュアルにある通り sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
で起動します。ここで多くの質問に答えると、設定ファイルができあがります。
なお、質問事項には StatsD
や CollectD
を使うかどうかの質問がありますが、使う回答をするとインストールとかがちょっと面倒なので、ここでは使いません😅
Do you want to turn on StatsD daemon? 1. yes 2. no default choice: [1]: 2 Do you want to monitor metrics from CollectD? WARNING: CollectD must be installed or the Agent will fail to start 1. yes 2. no default choice: [1]: 2
全部の質問に答えると The config file is also located at /opt/aws/amazon-cloudwatch-agent/bin/config.json.
みたいなメッセージが出力されるので、ここで設定ファイルのファイルパスを知ることになります。
CloudWatch Agent のコマンドいろいろ
EC2上で動くUbuntuの場合、です。オンプレやWindowsなど、環境が変われば当然にコマンドは変わります。
なお、本来は sudo
で作業するべきだろうとは思いますが、ここでは雑にroot権限で作業する前提になっています😇
- 設定ファイルを食わせて起動 :
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
- プロセスの状況を確認 :
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status
トラブルの内容
設定ファイルを食わせて起動しようとしたところ、Agentさんが上手く起動してくれませんでした。時系列で話を書いても読みにくくて仕方ないので、「こういう間違いをしたら、こういうエラーになった」という情報をいくつか列挙するという書き方でトラブルを紹介したいと思います。
トラブル1:設定ファイルがJSONとして正しくないとき
設定ファイルを食わせて起動しようとすると、コマンドは正常っぽく終了しますし、「Configuration validation succeeded」って言ってますし、終了ステータスは 0
です。よく見ると「unable to parse json」と言われていますが、これは容易に見落とします。
その後に稼働状況を見ても status: stopped
のままです。
root@ip-172-31-21-121:/opt/aws/amazon-cloudwatch-agent/bin# /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json ****** processing amazon-cloudwatch-agent ****** I! Trying to detect region from ec2 D! [EC2] Found active network interface I! imds retry client will retry 1 timesSuccessfully fetched the config and saved in /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_config.json.tmp Start configuration validation... 2023/11/23 11:18:27 Reading json config file path: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_config.json.tmp ... 2023/11/23 11:18:27 unable to scan config dir /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d with error: unable to parse json, error: invalid character 'a' looking for beginning of value 2023/11/23 11:18:27 No json config files found, use the default one 2023/11/23 11:18:27 I! Valid Json input schema. 2023/11/23 11:18:27 D! ec2tagger processor required because append_dimensions is set 2023/11/23 11:18:27 D! pipeline hostDeltaMetrics has no receivers 2023/11/23 11:18:27 Configuration validation first phase succeeded I! Detecting run_as_user... I! Trying to detect region from ec2 D! [EC2] Found active network interface I! imds retry client will retry 1 times /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -schematest -config /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml Configuration validation second phase succeeded Configuration validation succeeded amazon-cloudwatch-agent has already been stopped root@ip-172-31-21-121:/opt/aws/amazon-cloudwatch-agent/bin# echo $? 0 root@ip-172-31-21-121:/opt/aws/amazon-cloudwatch-agent/bin# /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status { "status": "stopped", "starttime": "", "configstatus": "configured", "version": "1.300031.0b313" }
※見やすさのために、コマンド間に空行を入れています。
なお、ログが /opt/aws/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log
に吐かれますが、その内容は以下のようなものでした。
2023/11/23 11:18:28 I! Return exit error: exit code=99 2023/11/23 11:18:28 I! No json config files found, please provide config, exit now
config file が無いみたいなことを言っていることから、私は誤った調査を進めてしまい、時間を浪費しました。
トラブル2:multi_line_start_pattern に与える正規表現が、正規表現として正しくないとき
CloudWatch Logs にログを送信する際、デフォルトでは、テキストファイルとしての1行(つまり改行文字ごとに1行)として処理されます。多くの場合はこれで良いのですが、アプリケーションのログが1つのエントリの途中で改行文字を出すことがある場合(例:スタックトレース)、CloudWatch Logs でログを参照する際の見易さが最悪の状態になります。filterが上手く機能しなくなるのです。なので、そのようなログを処理する際は multi_line_start_pattern
の設定が重要です。
アプリケーションのログが、論理的な1行(1つのエントリ)の最初に必ずタイムスタンプを吐くようであれば "multi_line_start_pattern": "{datetime_format}",
と書くことができ(別途 datetime_format
の設定が必要)、便利です。そうではない場合は正規表現を書くことになりますが、この書き方を間違えると、トラブルになります。
- エスケープシーケンス
\
の使い方を誤った場合- 例えば
"multi_line_start_pattern": "^\["
と書くと、起動時のメッセージにはunable to parse json, error: invalid character '[' in string escape code
と出ます。起動はしません。 - こう書きたい場合は、正しくは
"multi_line_start_pattern": "^\\["
のように、エスケープシーケンスを2つ重ねることになります。JSON Parse の段階でescapeとして処理されてしまうから、ですね。 - この誤りは、前述の「JSONとして正しくないとき」と、本質的には同じということになります。
- 例えば
- JSON parseは成功するけれども、正規表現として正しくない文字列を入れた場合
- 例えば
"multi_line_start_pattern": "*"
と書くと、起動には成功しますが、ログは CloudWatch Logs には送信されません。Agentのログ/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log
には2023-11-23T11:39:36Z W! [inputs.logfile] not started with file state folder %s/opt/aws/amazon-cloudwatch-agent/logs/state
といったログが1秒に1行、出力されます。このエラーメッセージから、原因が正規表現の誤りであることに気付くのは、なかなか難しいと思います。
- 例えば
- 空文字列を与えた場合
"multi_line_start_pattern": ""
とすると、以下のようなメッセージが出て、そもそもAgentの起動にも明示的に失敗します。ここだけとても親切ですw
root@ip-172-31-21-121:/opt/aws/amazon-cloudwatch-agent/bin# /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json ****** processing amazon-cloudwatch-agent ****** I! Trying to detect region from ec2 D! [EC2] Found active network interface I! imds retry client will retry 1 timesSuccessfully fetched the config and saved in /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_config.json.tmp Start configuration validation... 2023/11/23 11:47:30 Reading json config file path: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_config.json.tmp ... 2023/11/23 11:47:30 E! Invalid Json input schema. 2023/11/23 11:47:30 E! Invalid Json input schema. 2023/11/23 11:47:30 Under path : /logs/logs_collected/files/collect_list/0/multi_line_start_pattern | Error : String length must be greater than or equal to 1 2023/11/23 11:47:30 Configuration validation first phase failed. Agent version: 1.0. Verify the JSON input is only using features supported by this version. root@ip-172-31-21-121:/opt/aws/amazon-cloudwatch-agent/bin# echo $? 1
さいごに
日本語でこんなことを喋っていても世界は救えないので、issueをreportしました。
このメモで言及した内容は、バグ管理という意味では2つに分けるのが妥当だと思ったので、分けて報告しました。
環境情報
- Ubuntu 22.04 の公式のAMIから起こした EC2 instance
- t4g.nano
- CloudWatch Agent version
1.300031.0b313
- バージョン番号は
/opt/aws/amazon-cloudwatch-agent/bin/CWAGENT_VERSION
ファイルに書いてあります。
- バージョン番号は
- 作業は Session Manager の接続で実施