LoginSignup
0

More than 1 year has passed since last update.

posted at

CloudWatchLogsとLambdaを使ったエラーログ監視をしてみる

はじめに

エラーログ。。簡単にキーワードでひっかけてSlack通知させたいなぁ。。
そんなお悩みありませんか?
AWS上で運用されているかた必見!
かーんたんに(そしてわりと安く)ログ監視できちゃう方法をお披露目したいと思います!

構成

ScreenShot_2020-12-12_05.41.33.png

やり方

  1. CloudWatchAgentをEC2に導入する
  2. Lambdaの処理を書く
  3. ロググループにサブスクリプションフィルターを設定する

1. CloudWatchAgentをEC2に導入する

ポリシーが必要になるので、以下を参考にアタッチしてください。
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/create-iam-roles-for-cloudwatch-agent.html#create-iam-roles-for-cloudwatch-agent-roles

インストールはAmazonLinux2を利用してる場合以下で一発導入可能。

$ sudo yum install amazon-cloudwatch-agent

その他のサポート対象OSをお使いの場合はこちらを参考に導入してみてください!
サポート対象OSについては以下をご確認ください。
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html

導入が済んだら、設定ファイルを書いて起動してみましょう!
起動方法はOSによって異なるので、OSに合わせた起動方法で起動してください。
設定例

{
  "agent": {
    "run_as_user": "root"
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/hoge_service/fuga.log",
            "log_group_name": "/aws/ec2/hoge_service/fuga.log",
            "log_stream_name": "{instance_id}"
          }
        ]
      }
    }
  }
}

log_stream_nameはinstance_idを使うと手っ取り早くEC2毎にログストリームをわけてくれてオススメ設定です。
複数サーバーで使う場合は同じストリームにしないようにした方が良いでしょうね。
(理由は。。試せばわかりますw)
サーバー毎に監視したいエラーメッセージなどが異なる場合はlog_group_nameをサーバー毎にわける必要があります。
例: サーバーAではHogeErrorを監視する必要があって、サーバーBではFugaErrorを監視する必要がある場合は、サーバーAとサーバーBでlog_group_nameを分ける必要がある。

CloudWatchAgentはこの他にも色々な事ができて便利なので、気になる方は試してみてください。

2. Lambdaの処理を書く

CloudWatchLogsからトリガーされてSlack通知をするちょうど良いサンプルがPythonであったので、Pythonにしてます。
Lambdaがサポートしているお好きな言語で書くと良いと思います。
尚、Slackへの通知はIncoming webhookを想定して書いてます。
Incoming webhookの使い方は各自お調べください。
ログストリーム名をEC2のインスタンスIDとしているのでAWSコンソール上のEC2詳細画面へのリンクを生成して通知メッセージに入れてます。(オススメ!!)
またロググループへの遷移もできるようにしているので、前後のログ状況が通知後すぐに確認できます。(オススメ!!)

import base64
import requests, json
import urllib
import zlib
import datetime
import os
import boto3
import pprint
from botocore.exceptions import ClientError

print('Loading function')


def lambda_handler(event, context):
    data = zlib.decompress(base64.b64decode(event['awslogs']['data']), 16+zlib.MAX_WBITS)
    data_json = json.loads(data)
    WEB_HOOK_URL = "https://hooks.slack.com/services/hoge/fuga/XXXXXXX"
    WIKI_LINK_TITLE = "<https://hoge.fuga/wiki/HogeError|WIKI>"

    for log in data_json["logEvents"]:
        log_json = json.loads(json.dumps(log, ensure_ascii=False))
        #print(log_json)

        LOG_GROUP_LINK_TITLE = "<https://ap-northeast-1.console.aws.amazon.com/cloudwatch/home?region=ap-northeast-1#logsV2:log-groups/log-group/%s/log-events/%s|%s>" % (urllib.parse.quote_plus(data_json['logGroup']),data_json['logStream'],data_json['logGroup'])
        INSTANCE_ID_LINK_TITLE = "<https://ap-northeast-1.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-1#InstanceDetails:instanceId={0}|{0}>".format(data_json['logStream'])

        print("LOG_GROUP : %s" % data_json['logGroup'])
        print("STREAM_NAME : %s" % data_json['logStream'])

        try:

            message = u':no_entry:HOGEエラーが発生しました。\nサーバーの状態を確認して%sを参考に対応してください。\nロググループ名:%s\nインスタンスID:%s\nエラーメッセージ:\n```\n%s\n```' % (WIKI_LINK_TITLE,LOG_GROUP_LINK_TITLE,INSTANCE_ID_LINK_TITLE,log_json['message'])

            requests.post(WEB_HOOK_URL, data = json.dumps({
                'channel': u'#XXXXXXX',
                'text': message,  #通知内容
                'username': u'Alart From AWS lambda'  #ユーザー名
            }))

        except Exception as e:
            print(e)

    print('End function')

requestsライブラリが外部パッケージとなっているため、pipなどでダウンロードしてzipで固めてuploadする必要があります。
以下Mac上で対応した例です。
最後にlambda_function.pyを忘れずに入れてディレクトリごとzipで固めてuploadすれば幸せになれます。

$ mkdir for_lambda
$ cd for_lambda/
$ pip3.7 install requests -t .
Collecting requests
  Downloading https://files.pythonhosted.org/packages/39/fc/f91eac5a39a65f75a7adb58eac7fa78871ea9872283fb9c44e6545998134/requests-2.25.0-py2.py3-none-any.whl (61kB)
     |████████████████████████████████| 61kB 7.1MB/s 
Collecting chardet<4,>=3.0.2
  Using cached https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl
Collecting urllib3<1.27,>=1.21.1
  Downloading https://files.pythonhosted.org/packages/f5/71/45d36a8df68f3ebb098d6861b2c017f3d094538c0fb98fa61d4dc43e69b9/urllib3-1.26.2-py2.py3-none-any.whl (136kB)
     |████████████████████████████████| 143kB 9.9MB/s 
Collecting certifi>=2017.4.17
  Downloading https://files.pythonhosted.org/packages/5e/a0/5f06e1e1d463903cf0c0eebeb751791119ed7a4b3737fdc9a77f1cdfb51f/certifi-2020.12.5-py2.py3-none-any.whl (147kB)
     |████████████████████████████████| 153kB 10.2MB/s 
Collecting idna<3,>=2.5
  Using cached https://files.pythonhosted.org/packages/a2/38/928ddce2273eaa564f6f50de919327bf3a00f091b5baba8dfa9460f3a8a8/idna-2.10-py2.py3-none-any.whl
Installing collected packages: chardet, urllib3, certifi, idna, requests
Successfully installed certifi-2020.12.5 chardet-3.0.4 idna-2.10 requests-2.25.0 urllib3-1.26.2
$ ll
total 0
drwxr-xr-x   3 hoge_fuga  1189740132    96 12 12 06:58 bin
drwxr-xr-x   7 hoge_fuga  1189740132   224 12 12 06:58 certifi
drwxr-xr-x   8 hoge_fuga  1189740132   256 12 12 06:58 certifi-2020.12.5.dist-info
drwxr-xr-x  43 hoge_fuga  1189740132  1376 12 12 06:58 chardet
drwxr-xr-x  10 hoge_fuga  1189740132   320 12 12 06:58 chardet-3.0.4.dist-info
drwxr-xr-x  11 hoge_fuga  1189740132   352 12 12 06:58 idna
drwxr-xr-x   8 hoge_fuga  1189740132   256 12 12 06:58 idna-2.10.dist-info
drwxr-xr-x  21 hoge_fuga  1189740132   672 12 12 06:58 requests
drwxr-xr-x   8 hoge_fuga  1189740132   256 12 12 06:58 requests-2.25.0.dist-info
drwxr-xr-x  17 hoge_fuga  1189740132   544 12 12 06:58 urllib3
drwxr-xr-x   8 hoge_fuga  1189740132   256 12 12 06:58 urllib3-1.26.2.dist-info
$ touch lambda_function.py 

3. ロググループにサブスクリプションフィルターを設定する

CloudWatchAgentの設定がうまくいってログが転送され出すと、CloudWatchLogsに設定ファイルに設定したロググループ名でロググループが追加されていると思います。
今すぐAWSコンソールを開いて確認してみましょう!
必要に応じてログの保持期間などを変更しておきましょう。
ロググループの一覧からでも詳細からでも構いませんので、アクションからLambda サブスクリプションフィルターを作成を選択します。
以下を参考に設定してみましょう。
サブスクリプションフィルター設定例.png
一つのロググループに対して最大で二つのサブスクリプションフィルターが作成できます。(サポートにて確認済み)
また、面倒ですが、一度登録したサブスクリプションフィルターはLambda側でのみ削除できます。
AWS CLIを使えばこの限りではないと思います。(そこまでは調べてないです。。)
うまく連携できるとLambda側で以下のように確認できます。

連携確認.png
ここまでできれば、Slack通知されるはずです!
できてなかったら、Lambdaの実行ログなどを確認してトラブルシューティング頑張ってください!

おわりに

比較的コーディング少なめでログの監視ができるものです。
ElasticSearch版のサブスクリプションフィルターもあるようなので、より高度なログ解析のできるようです。
機会があれば、チャレンジしてみたいものです^^

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0