vague memory

うろ覚えを無くしていこうともがき苦しむ人の備忘録

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

f:id:htnosm:20160505000213p:plain

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

f:id:htnosm:20160504231804p:plain

(2) Stream to AWS Lambda でSlack通知

各種設定

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

Lambda Function 作成

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

f:id:htnosm:20160504231806p:plain

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実行

f:id:htnosm:20160504231807p:plain

Metric Filter 作成

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

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

f:id:htnosm:20160504231816p:plain

  • 作成した Lambda Function を指定

f:id:htnosm:20160504231809p:plain

  • Filter Pattern を設定

f:id:htnosm:20160504231810p:plain f:id:htnosm:20160504231811p:plain

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

Subscription に Lambda が表示されます。

f:id:htnosm:20160504231812p:plain

Metric Filter の追加

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

f:id:htnosm:20160504231813p:plain

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

f:id:htnosm:20160504231814p:plain

通知例

f:id:htnosm:20160504231815p:plain


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