CloudWatch LogsでAmazonLinux上のApacheエラーログを監視する
はじめに
こんにちは、虎塚です。
ログファイルの監視ができるAWSサービスといえば、CloudWatch Logsですね。メトリックを使ってアラームを設定し、SNSと組み合わせることで、アラートメールも送信できます。
本ブログでも、これまでに何度かCloudWatch Logsをご紹介してきました。
- Amazon CloudWatch Logsでログファイルを監視する | Developers.IO
- Amazon CloudWatch Logsによるログの収集とフィルタとアラーム設定 | Developers.IO
CloudWatch Logsは、2014年7月にリリースされたサービスです。この半年ほどで、いくつか機能アップデートがありました。主なアップデートは、次のとおりです。
- CloudWatch Logsが東京リージョン(ap-northeast-1)でも利用できるようになりました(2014年12月)
- Amazon LinuxでCloudWatch Logsエージェントをパッケージからインストールできるようになりました
- JSONログフォーマットに対応しました(2015年1月)
今日は、主に初心者の方向けに、あらためてCloudWatch Logsの使い方をご紹介します。
今回CloudWatch Logsで実現する内容
東京リージョンに起動したAmazon LinuxのEC2で、Apache HTTP Serverを運用します。そのエラーログをCloudWatch Logsで監視して、404エラーを表わす「File does not exist」の文字列が5分間に20回以上出現した場合、あらかじめ決めたメールアドレスにアラートメールを送信します。
なお、Amazon Linuxは、Amazon Linux AMI 2014.09.2 (HVM)を利用して動作確認をおこないました。
手順
0.準備: EC2を起動する
次の設定でEC2インスタンスを起動します。
- Public IPアドレスの自動アサイン
- ブラウザからApacheにアクセスして動作確認をするため、Public IPアドレスが自動的にアサインされるようにします
- セキュリティグループで22番と80番ポートのアクセスを許可
- CloudWatch Logsエージェントの設定と動作確認のため、SSHとHTTPによるアクセスを許可します
- CloudWatch Logsへの変更権限のあるIAMロールを設定
- 後述します。
IAMロールについて、少し補足します。
IAMロールを付与してEC2を起動する
CloudWatch Logsエージェントは、内部でAWS CLIを実行して、CloudWatch Logsにログのデータをpushします。そのため、CloudWatch LogsエージェントをインストールするEC2には、関連するAWS APIを実行できるIAMポリシーを定義したIAM Roleを紐づけます。
(IAM Role for EC2についてわからない場合は、IAM roles for EC2 instancesを使ってみる」あたりを参照してください)
IAMポリシーの作成メニューで「CloudWatch Logs Full Access」を選ぶと、今回の用途に必要な権限をもつIAMポリシーを作ることができます。もっと権限の大きいポリシー(たとえばPower Userなど)でも構いません。
Apacheをインストールして起動する
上記の設定でインスタンスを起動したら、SSHでログインします。システム全体のパッケージをアップデートしてから、Apacheをインストールして起動します。
$ sudo yum update -y $ sudo yum install -y httpd $ sudo service httpd start
EC2のPublic IPアドレスを確認してブラウザからアクセスし、Apacheの初期ページが表示されることを確認しておきましょう。
1. CloudWatch Logsエージェントのインストール
以前はPython製のスクリプトでCloudWatch Logsエージェントをインストールしていましたが、最近のAmazon Linuxでは、CloudWatch Logsをパッケージインストールできるようになりました。他のLinuxディストリビューションでは、現在もスクリプトを使ってインストールします。
なお、以前スクリプトでインストールしたエージェントを、パッケージインストールでアップデートすることはできませんので、ご注意ください。公式ドキュメントによると、ログの転送に不具合が出る恐れがあるそうです。
CloudWatch Logsエージェントを次のコマンドでインストールします。
$ sudo yum install -y awslogs [...] ================================================================================ Package アーキテクチャー バージョン リポジトリー 容量 ================================================================================ インストール中: awslogs noarch 1.1.0-1.3.amzn1 amzn-main 7.7 k 依存性関連でのインストールをします: aws-cli-plugin-cloudwatch-logs noarch 1.2.0-1.7.amzn1 amzn-updates 61 k トランザクションの要約 ================================================================================ インストール 1 パッケージ (+1 個の依存関係のパッケージ) 総ダウンロード容量: 69 k インストール容量: 203 k [...]
2. CloudWatch Logsエージェントの設定
まず、AWS CLIの設定をします。今回は東京リージョンでCloudWatch Logsを使いますので、ログをpushするregionの値を変更しておきます。
[plugins] cwlogs = cwlogs [default] region = ap-northeast-1
次に、CloudWatch Logsへ転送するログ情報を定義します。エージェント設定ファイルの末尾に、次のテキストを追加します。
[/etc/httpd/logs/error_log] log_group_name = example.com/Apache/error_log log_stream_name = {instance_id}_httpd_error file = /etc/httpd/logs/error_log datetime_format = [%a %b %d %H:%M:%S %Y] initial_position = start_of_file buffer_duration = 5000
- [セクション名] (必須)
- ログ転送情報を定義するセクションの目印。設定ファイル内で一意になるように定義します。ここで記述した値は、Management Consoleから見えませんので、何でもよいと思いますが、ここではファイルパスにしました。
- log_group_name (必須)
- ログストリームのグループ。ロググループ:ログストリームは、1:(1以上の)nの関係になります。ロググループに対して、転送したログの保存期間やメトリックフィルタを設定できます。
- log_stream_name (必須)
- 送信先のログストリーム名。指定した名前が存在しなければ作成されます。定義済み変数として、{instance_id}、{hostname}、{ip_address}が使えます。なお、複数のログを1つのストリームに送ることはできません。
- file (必須)
- pushするログファイルのパスを記述します。末尾にワイルドカードを使えます
- datetime_format (必須ではありませんが指定しましょう *後述)
- 日付フォーマット。正しく指定することで、タイムスタンプをCloudWatch Logs側に取り込むことができます。
- initial_position
- ログファイルの詠み込み開始位置。start_of_fileまたはend_of_fileを指定します。
- buffer_duration
- ログイベント発生のバッファをミリ秒で指定します。
必須項目を設定しなかった場合、CloudWatch Logsエージェント自体のログ(/var/log/awslogs.log)に、次のようなエラーが出力されます。
No option 'log_group_name' in section: '{セクション名}'
No option 'log_stream_name' in section: '{セクション名}'
datetime_formatについて
datetime_formatは、CloudWatchが、受け取ったログデータからタイムスタンプを見分け、Creation Dataとして保持するために必要です。
エージェント側でdatetime_formatの設定を省略すると、現在時刻がCreation Dataとして使われます。また、無効なdatetime_formatを設定すると、有効なdatetime_format定義によって入手できた最後の値(それがなけれが現在時刻)が使われます。
Creation Dataは、CloudWatchでログをフィルタするために利用できます。CloudWatchにログが転送された時刻ではなく、実際にログ出力されたタイムスタンプをCreation Dataとみなした方が、精確なフィルタができると思います。そのため、必須項目ではありませんが、datetime_formatを設定するようにしましょう。
たとえば、Apacheのエラーログは、デフォルトで次のようなフォーマットです。
[Thu Mar 05 05:43:02 2015] [error] [client 20X.XXX.XX.XX] File does not exist: /var/www/html/foo.html
先頭のタイムスタンプにマッチするフォーマットは、次のとおりです。
[%a %b %d %H:%M:%S %Y]
3. CloudWatch Logsエージェントの開始
CloudWatch Logsエージェントを開始します。
$ sudo service awslogs start
なお、設定ファイルを変更した際には、変更を適用するためにエージェントのrestartが必要です。
$sudo service awslogs restart Stopping awslogs: [ OK ] Starting awslogs: [ OK ]
4. ログ転送の動作確認
先ほどブラウザからアクセスしたEC2のIPアドレスに、存在しないファイル名やディレクトリ名を続けてアクセスし、Apacheのエラーログを出力してみましょう(http://XXX.XXX.XXX.XXX/foo-bar.htmlなど)。数秒後、CloudWatchのダッシュボードでログが表示されれば、ログがCloudWatch Logsへ転送されています。
参考までに、datetime_formatの設定によってログデータからタイムスタンプが正しく取り出された様子と、設定ミスをして取り出しに失敗した様子を、比較して紹介します。
※Creation Time列が画面に表示されない場合は、一覧の右上にある歯車アイコンをクリックして、表示項目を変更します。
datetime_formatに無効な指定をして、CloudWatchがログデータから正しくタイムスタンプを取り出せなかった場合、図の赤枠内のようにログデータ内のタイムスタンプ(Event Data)とイベント発生時刻(Creation Data)にズレが生じます。正しく指定した場合、図の緑枠内のように、Event DataとCreation Dataが一致します。
5. SNSの設定
アラームを発生させてメールを受け取るために、SNSのトピックを作成します。SNSのダッシュボードで、任意の名前をつけたSNS Topicを作成します。ここではTopic Nameを「test-logs」にしました。
Topics一覧でそのTopicを選び、[Other actions]から[Subscribe to topic]を選びます。ProtocolにEmailを選び、EndpointにEメールアドレスを入力して保存します。
入力したメールアドレスに、Subscribe確認のメールがno-reply@sns.amazonaws.comから届きます。メール本文のリンクをクリックしましょう。
6. メトリックフィルタの作成
CloudWatchのダッシュボードで、Log Groups一覧から先ほど登録したロググループを選び、[Create Metric Filter]ボタンを押します。
ログを抽出する文字列として、Filter Patternに「"File does not exist"」と入力します。この設定を使って、のちほどアラームを作成できます。
[Assign Metric]ボタンを押して次の画面に進み、FilterとMetricに名前をつけて保存します。ここでは、Filter Nameを「File-does-not-exist」、Metric Nameを「httpd-404」にしました。
7. アラームの作成
CloudWatchのダッシュボードで、ふたたびLog Groups一覧から先ほど登録したロググループを選び、今度は[Metric Filters]列の値をクリックします(ロググループに対して設定したメトリックフィルタの個数が表示され、リンクが張られているかと思います)。
先ほど登録したメトリックフィルタに対して、アラームを作成しましょう。
設定のポイントを補足します。
- Name
- アラームの名前。通知メールのSubjectは「ALARM: "{アラーム名}" in APAC - Tokyo」というフォーマットになるので、実際に使う時はわかりやすい名前をつけましょう。
- Whenever、Period、Statistic
- メトリックでフィルタされたログの合計値が、5分で20回以上になることが、アラーム状態になる条件となるように設定します
- Send notification to
- アラームの通知先として、先ほど作成したSNSのトピックを選びます
8. アラームの動作確認
これで設定は完了です。
存在しないURIに繰り返しアクセスして、「404エラーを5分以内に20回以上」発生させましょう。アラームが上がり、登録したメールアドレス宛にメールが届けば、動作確認は成功です。
おわりに
CloudWatch Logsを使ってApacheのエラーログを転送し、閾値を設定して監視した上で、閾値を超えたらメール通知する方法を説明しました。
ログ管理まわりでCloudWatch Logsが役立ちそうな場面を、いろいろと想像していただければ幸いです。
それでは、また。