share facebook facebook2 twitter menu hatena pocket slack

2016.06.06 MON

AWS Lambda で CloudWatch Logs のログ本文をSlack通知(2)

WRITTEN BY大住 孝之

20160505000213-1

前回 AWS Lambda で CloudWatch Logs のログ本文をSlack通知(1) の続きです。
SNSを介さず、Lambdaから直接Slackへ投稿する方法です。

20160504231804-1

(2) Stream to AWS Lambda でSlack通知

各種設定

Blueprints冒頭に記載されている Slack Integration や KMS の設定については割愛します。

Lambda Function 作成

  • [Services] -> [Lambda] -> [Create a Lambda Function]

20160504231806

cloudwatchlog-alarm-to-slack.py

今回使用するFunctionです。 Blueprintと同様に ENCRYPTED_HOOK_URL、SLACK_CHANNEL にSlackの設定値を入れます。

from __future__ import print_function

import base64
import json
import zlib
import datetime
import boto3
import logging

from base64 import b64decode
from urllib2 import Request, urlopen, URLError, HTTPError

ENCRYPTED_HOOK_URL = ''  # Enter the base-64 encoded, encrypted key (CiphertextBlob)
SLACK_CHANNEL = '#'  # Enter the Slack channel to send a message to

HOOK_URL = "https://" + boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED_HOOK_URL))['Plaintext']

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    data = zlib.decompress(base64.b64decode(event['awslogs']['data']), 16+zlib.MAX_WBITS)
    data_json = json.loads(data)
    log_json = json.loads(json.dumps(data_json["logEvents"][0], ensure_ascii=False))
    if data_json["logGroup"]:
        date = datetime.datetime.fromtimestamp(int(str(log_json["timestamp"])[:10])) + datetime.timedelta(hours=9)
        message = str(date) + " [CloudWatch Log Alarm] " + data_json["logGroup"] + " / " + data_json["logStream"] + "nLogMessages:"
        logger.info(data_json)
        for e in data_json["logEvents"]:
            message = message + 'n' + e['message']
            logger.info("LogMessage: " + str(message))

        slack_message = {
            'channel': SLACK_CHANNEL,
            'text': "%s" % (message)
        }

        req = Request(HOOK_URL, json.dumps(slack_message))
        try:
            response = urlopen(req)
            response.read()
            logger.info("Message posted to %s", slack_message['channel'])
        except HTTPError as e:
            logger.error("Request failed: %d %s", e.code, e.reason)
        except URLError as e:
            logger.error("Server connection failed: %s", e.reason)

IAM role 設定

Lambda Function 作成時に指定した Role に下記が実行できるよう権限を付与します。

  • lambda_basic_execution (Function作成時に付与するポリシー)
  • KMS復号化
  • filter-log-events実行

20160504231807

Metric Filter 作成

CloudWatch Logs からメトリックフィルタを作成します。

  • CloudWatch -> Logs -> LogGroup -> Stream to AWS Lambda

20160504231816

  • 作成した Lambda Function を指定

20160504231809

  • Filter Pattern を設定

20160504231810

20160504231811

  • 設定後のロググループ一覧

Subscription に Lambda が表示されます。

20160504231812

Metric Filter の追加

CloudWatch 側からだけでなく、 Lambda 側からもメトリックフィルタの追加が可能です。

20160504231813

  • [Lambda] -> [Function] -> [Event source]

20160504231814

通知例

20160504231815

CloudWatchLogsにログを転送していることが前提ですが、 EC2インスタンスに手を入れずにログ監視が行えます。
それ程クリティカルでなく、監視エージェントを導入する程では無いのであれば、 実装候補に入りうると思います。

元記事はこちら

AWS Lambda で CloudWatch Logs のログ本文をSlack通知(2)

大住 孝之

構築運用担当。 個性的な面々の中で無個性という個性を打ち出していこうと画策中。