プロジェクト

全般

プロフィール

第6回:EC2上のjavaアプリケーションのログをCloudWatch Logsに流してExceptionの発生を監視してみる

(2022/2/9 19:00開催)

第5回ではAutoScalingを使って、インスンタンスを自動でスケールアウト/スケールインさせてみました。
一方、アプリケーションログはそれぞれのサーバーインスタンスに出力されるので、スケールインによってインスタンスが終了してしまうと見れなくなってしまいます。
今回は、そのような問題に対応するためにアプリケーションログをCloudWatch Logsというサービスに転送してみます。
(CloudWatch agentはEC2インスタンスだけでなくオンプレのサーバーにインストールしてログを転送することも可能です)

さらに、転送されたCloudWatch Logsのログを監視することで例外が発生したことを検出し、通知のサービスであるAmazon SNS(SimpleNotificationService)を使って自分のメールアドレスに送信してみます。
amazon SNSはモバイルアプリケーションへのpushサーバーとしても利用することができます(AndroidやiOSアプリへのAPNsやFCMを利用したpush通知が可能)。※今回は利用しません


ハンズオン

全体の流れは下記のようになります。

  • EC2にアタッチするIAMRoleの作成
  • EC2インスタンスの起動
  • Javaアプリケーションのデプロイ
  • CloudWatch agentのインストールと設定
  • CloudWatch Logsにログが転送されることの確認
  • SNSのリソース作成とメール通知設定
  • CloudWatch Logsの例外監視と通知の設定
  • 通知の確認
  • リソース削除

■ EC2にアタッチするIAMRoleの作成

  • 「CloudWatchAgentServerPolicy」のAWSマネージドIAMポリシーを設定したEC2用のIAMロールを"study2-ec2-cwagent"という名前で作成します。(名前は適当です)

■ EC2インスタンスの起動

※ IAMロールには先程の手順で作成した"study2-ec2-cwagent"をアタッチします

■ Javaアプリケーションのデプロイ

勉強会第2回目で使ったjavaアプリケーションにログ出力を追加したものを使います。
このjavaアプリケーションは"/test/status"のパスに"cd"のクエリパラメータに返却させたい任意のHTTPステータスコードを設定してGETリクエストを行うことで、指定したステータスコードでレスポンスを返却できるように実装されています。
また、"起動ディレクトリ/study2"ディレクトリの下に"demo_web.log"というファイル名でログファイルが出力される設定になっており、5xx系のエラーコードの場合に例外のスタックトレースも出力されるようになっています。

  • javaのインストール(ここではAWSが提供するOpenJDKのCorrettoの11をインストールします)
sudo yum install java-11-amazon-corretto-headless -y
  • 下記コマンドでjarファイルをダウンロード。
wget https://redmine.apps.kinocoffeeblack.net/attachments/download/209/demo_web.jar
  • デモアプリケーションの起動
java -jar demo_web.jar &
  • curlコマンドで動作確認(EC2インスタンスにログインした状態で)
curl -i localhost:8080/
curl -i localhost:8080/test/status?cd=500
  • "study2/demo_web.log"ログファイルが出力されていることを確認

■ CloudWatch agentのインストールと設定

  • CloudWatch agentのインストール
sudo yum install amazon-cloudwatch-agent -y
  • 設定ファイルを配置
wget https://redmine.apps.kinocoffeeblack.net/attachments/download/206/amazon-cloudwatch-agent.json
sudo cp amazon-cloudwatch-agent.json /opt/aws/amazon-cloudwatch-agent/etc/

※jsonファイルの内容

{
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/home/ec2-user/study2/demo_web.log",
            "log_stream_name": "{instance_id}",
            "log_group_name": "/study2/demo_web",
            "timestamp_format": "%d/%b/%Y:%H:%M:%S %z",
            "timezone": "UTC"
          }
        ]
      }
    }
  }
}
  • CloudWatch agentの起動
sudo systemctl start amazon-cloudwatch-agent.service
sudo systemctl status amazon-cloudwatch-agent.service

■ CloudWatch Logsにログが転送されることの確認

  • CloudWatchのコンソール画面を開いて"/study2/demo_web"のロググループを確認

■ SNSのリソース作成とメール通知設定

  • SNSの画面を開いて"Study2TestTopic"を作成(タイプはスタンダードを選択、表示名に"Study2てすと"を入力)
  • 「サブスクリプションを作成」からプロトコル=Eメールのサブスクリプションを作成。エンドポイントに自分が受信可能な任意のEメールアドレスを設定。
  • メールを受信するので、メール内の「Confirm subscription」リンクから"確認"アクションを行う(これによりステータスが保留中から確認済みになる)

■ CloudWatch Logsの例外監視と通知の設定

●ログの監視設定(メトリクスフィルターの作成)

  • CloudWatchのコンソール画面を開いて"/study2/demo_web"のロググループを確認
  • 「メトリクスフィルター」タブ > 「メトリクスフィルターを作成」
  • フィルターパターンに"TestException"を設定 > パターンをテスト > Next
  • フィルター名"TestExceptionCountFilter"
    • メトリクス名前空間: study2/test
    • メトリクス名: TestExceptionCount
    • メトリクス値: 1、デフォルト値: 0

●ログの監視設定(Alarmの作成)

  • 作成されたメトリクスフィルターを表示 > アラームの作成
    • 統計: 合計
    • 期間: 1分
    • 条件: 1/1のデータポイントで1以上
    • 欠落データの処理: 欠落データを適正 (しきい値を超えていない)として処理
  • アクションの設定
    • アラーム状態トリガー: アラーム状態
    • 既存のSNSトピックから、前の手順で作成したものを選択
    • 次へ
  • 名前と説明を追加
    • アラーム名: Study2TestExceptionAlarm
    • 次へ > アラームの作成

■ 通知の確認

  • バックグラウンドで定期的(20秒ごと)に正常リクエスト( "curl -i localhost:8080/" )を行う
while [ 1 ]; do curl -i localhost:8080/ ; sleep 20; done > /dev/null 2>&1 &
  • 裏で↑を実行させつつ、curlコマンドで例外(TestException)を起こしてみる
curl -i localhost:8080/test/status?cd=500
  • しばし待って、メールを受信することを確認

    • すべてのメトリクス > study2/test > ディメンションなしのメトリクス > TestExceptionCount を選択
    • 「グラフ化したメトリクス」タブを表示 > 統計を"合計" に変更する
    • グラフの推移を監視する
  • (任意)バックグラウンドジョブをjobsコマンドでジョブ番号を調べてkillする

jobs
kill %ジョブ番号

■ リソース削除

  • EC2インスタンスを終了
  • CloudWatchのリソース削除(アラーム、ロググループ)
  • SNSのSubscribeとTopicを削除
  • IAMRoleを削除

■ 備考

  • 通知メッセージを素のままのではなく、見やすいように整形したい場合はアラームに紐付けるSNSTopicのサブスクリプションをLambdaにして整形処理 → AWS SDKを使って別のSNSTopicでメール通知ということも可能
  • SES(SimpleEmailService)というメールサーバのサービスがあり、「メールを送信できる」という意味ではSNSと同じような機能を持っているように見えますがSNSは通知のサービスなので事前にSubscriptionで登録した相手にしか送信することができません。一方SESはメールサーバーとして任意の相手に送信することができます(sendmailやfostfix,qmailのようなメールサーバーのAWSマネージドサービス版というイメージ)。

参考

CloudWatch エージェントを使用した Amazon EC2 Instances インスタンスとオンプレミスサーバーからのメトリクスとログの収集
Amazon SNS
【AmazonLinux2】【amazon-cloudwatch-agent】最速で Apache のアクセスログを CloudWatch Logs にログ出力してみる
初心者もCloudwatch Logsでサーバーログを監視してみよう
CloudWatch Logs メトリクスフィルターは 継続的にデフォルト値をメトリクスに発行しているわけではない