LambdaでCloudWatchにエラーログが流れたらAWS ChatbotでSlack通知するPython製CDKスタック

サーバーのエラーを監視するため、Lambda のログで CloudWatch に[ERROR]の文字列が含まれていたら、AWS Chatbot で Slack チャンネルへ通知するように Python 製 CDK スタックを作成しました。

目次

通知先の Slack チャンネルを作成し、Slack ワークスペース ID とチャンネル ID を確認する

通知先の Slack チャンネルを作成します。私の場合はサービスごと、環境ごと(dev, prod)で分けており、service-name-dev, service-name-prodのように名前をつけています。

Slack ワークスペース ID とチャンネル ID は、ブラウザ版 Slack を開けば確認できます

Slack ワークスペース ID とチャンネル ID を cdk.json に追加する

デプロイする際に CDK が参照できるように、cdk.json へ環境ごとに ID を追加します。

  "context": {
    "hoge": "fuga",
    "dev": {
      "slack_workspace_id": "hoge_dev",
      "slack_channel_id": "fuga_dev"
    },
    "prod": {
      "slack_workspace_id": "hoge_prod",
      "slack_channel_id": "fuga_prod"
    }
  }

AWS Chatbot で Slack workspace へのアクセス権限を付与する

AWS Chatbot は、指定された Slack ワークスペース ID とチャンネル ID にアクセスしますが、ID を知っているだけではアクセスできません。AWS Chatbot が Slack ワークスペースにアクセスする権限を AWS マネジメントコンソールから許可します。

AWSマネジメントコンソールから、ChatbotとSlackの連携認証をする画面

アクセス許可を出しておかないと、CDK でのデプロイ時にエラーになります。

10:50:25 | CREATE_FAILED | AWS::Chatbot::SlackChannelConfiguration | hoge_channel Resource handler returned message: "Invalid request provided: AWS Chatbot can't create the configuration because Slack workspace hoge1 is not authorized with AWS account 0000000000. See https://docs.aws.amazon.com/chatbot/latest/adminguide/setting-up.html#Setup_intro (Service: AWSChatbot; Status Code: 400; Error Code: InvalidRequestException; Request ID: xxxx; Proxy: null)"

CDK スタックで Chatbot と CloudWatch カスタムメトリクスを作る

少し長いですが、Chatbot と CloudWatch カスタムメトリクスを設定する CDK スタックの Python スクリプトです。try_get_context で、コマンドラインオプションと cdk.json から値を取得します。

Chatbot には CloudWatch を参照するための権限を付与しました。CloudWatch カスタムメトリクスのアラームが発火すると、SnsAction が実行されて Slack に通知が飛びます。

#
# エラーをSlack通知するチャットボット
#
stage = self.node.try_get_context('stage')
env = self.node.try_get_context(stage)
slack_channel_name = 'hoge_channel'
slack_channel = aws_chatbot.SlackChannelConfiguration(
    self,
    slack_channel_name,
    slack_channel_configuration_name=slack_channel_name,
    slack_workspace_id=env["slack_workspace_id"],
    slack_channel_id=env["slack_channel_id"]
)

slack_channel.add_to_role_policy(aws_iam.PolicyStatement(
    effect=aws_iam.Effect.ALLOW,
    actions=[
        "cloudwatch:Describe*",
        "cloudwatch:Get*",
        "cloudwatch:List*",
    ],
    resources=["*"]
))

alerm_sns_topic = aws_sns.Topic(self, 'alerm')
slack_channel.add_notification_topic(alerm_sns_topic)
sns_action = aws_cloudwatch_actions.SnsAction(alerm_sns_topic)

#
# 通知を発火するCloudWatchカスタムメトリクス
#
functions = [my_lambda_functions]
for function in functions:
    metric_filter_name = function._physical_name + '_error_metric_filter'
    metric_filter = function.log_group.add_metric_filter(
        metric_filter_name,
        filter_pattern=aws_logs.FilterPattern.any_term("[ERROR]"),
        metric_name="filter_pattern [ERROR]",
        metric_namespace=metric_filter_name,
        metric_value="1"
    )

    alarm = aws_cloudwatch.Alarm(
        self,
        function._physical_name + "_error_alarm",
        metric=metric_filter.metric(),
        threshold=1,
        evaluation_periods=1,
        comparison_operator=aws_cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
        treat_missing_data=aws_cloudwatch.TreatMissingData.NOT_BREACHING,
    )

    alarm.add_alarm_action(sns_action)

CDK を叩いてデプロイする

CDK を叩く際に stage=dev/prod を渡すことで、適切な Slack ワークスペース ID とチャンネル ID に通知が飛ぶようになります。

cdk deploy --profile hoge-dev --context stage=dev






Amazon欲しいものリスト

私が作業中に飲んでいるコーヒーや欲しいマンガなどを集めました。開発・執筆の励みになりますのでクリックして頂ければ幸いです。

<Amazon欲しいものリスト>