CloudWatch LogsでAmazonLinux上のApacheエラーログを監視する

CloudWatch

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、虎塚です。

ログファイルの監視ができるAWSサービスといえば、CloudWatch Logsですね。メトリックを使ってアラームを設定し、SNSと組み合わせることで、アラートメールも送信できます。

本ブログでも、これまでに何度かCloudWatch Logsをご紹介してきました。

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 https 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]列の値をクリックします(ロググループに対して設定したメトリックフィルタの個数が表示され、リンクが張られているかと思います)。

先ほど登録したメトリックフィルタに対して、アラームを作成しましょう。

CloudWatchでログにアラームを作成する

設定のポイントを補足します。

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が役立ちそうな場面を、いろいろと想像していただければ幸いです。

それでは、また。