[AWS CDK]Chatbotを使ってLambdaのエラーをSlackに通知してみた

単純にエラーを通知したいならChatbotを使えばこんなに見やすく通知してくれます。CDKでサクッと実装しましょう。
2023.01.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Lambda単体で動かす時、簡単にSlackに通知できる仕組みが欲しいなと思いCDKで実装してみました

いくつかLambdaのエラーを拾うための実装パターンはありますが、なるべく単純な仕組みが好ましかったため以下のサービスを利用しました。

やってみる

以下の環境で実装しました。

❯ cdk --version
2.59.0 (build b24095d)
❯ python  --version 
Python 3.8.13

事前準備

CDKでデプロイするだけにしたいところですが、Chatbotを利用する上でワークスペースとの接続はコンソールから実施する必要があります。

AWSコンソールにログインしてChatbotを開きます。チャットクライアントでSlackを選択してクライアントを設定をクリックしてください。

ワークスペースとの接続画面に飛ぶので、右上から通知先にしたいワークスペースを選択してから「許可する」でOKです。

ワークスペースの詳細画面に遷移するので、ワークスペースIDを控えておきましょう。CDK側で利用します。

あとは通知先にしたいチャンネルIDも控えておきましょう。

CDKのコード

実装するコードは以下の通りです。

[ワークスペースID][通知先のチャンネルID]は事前作業で控えたものに置き換えてください。

./lib/cdk-lambda-error-alert-stack.ts

import {
  aws_iam as iam,
  aws_lambda as lambda,
  aws_cloudwatch as cloudwatch,
  aws_cloudwatch_actions as cwactions,
  aws_chatbot as chatbot,
  aws_sns as sns,
  Stack,
  StackProps,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkLambdaErrorAlertStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const slackWorkspaceId = '[ワークスペースID]';
    const slackChannelId = '[通知先のチャンネルID]'

    const errorFn = new lambda.Function(this, 'ErrorFunc', {
      functionName: "error-func",
      runtime: lambda.Runtime.PYTHON_3_9,
      code: lambda.Code.fromAsset('./lambda'),
      handler: 'error-test.handler',
    });

    // SNSトピック
    const errorTopic = new sns.Topic(this, `ErrorTopic`, {
      displayName: `ErrorTopic`,
      topicName: `ErrorTopic`
    });
    // Chatbot用のIAMロール・ポリシー
    const chatbotRole = new iam.Role(this, "ChatbotRole", {
      roleName: "chatbot-sample-role",
      assumedBy: new iam.ServicePrincipal("chatbot.amazonaws.com"),
    });
    chatbotRole.addManagedPolicy(
      iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchLogsReadOnlyAccess')
    );
    chatbotRole.addToPolicy(
      new iam.PolicyStatement({
        resources: ["*"],
        actions: [
          "cloudwatch:Describe*",
          "cloudwatch:Get*",
          "cloudwatch:List*",
        ],
      })
    );

    // Chatbot設定
    const cb = new chatbot.SlackChannelConfiguration(this, `SlackChannelConfiguration`, {
      slackChannelConfigurationName: `SlackChannelConfiguration`,
      slackWorkspaceId: slackWorkspaceId,
      slackChannelId: slackChannelId,
      notificationTopics: [errorTopic],
      loggingLevel: chatbot.LoggingLevel.INFO,
      role: chatbotRole,
    });

    // CloudWatchアラーム
    const apiServerErrorAlarm = new cloudwatch.Alarm(this, `ErrorAlarm`, {
      alarmName: "error-func-alarm",
      threshold: 1,
      evaluationPeriods: 1,
      metric: errorFn.metricErrors(),
      datapointsToAlarm: 1,
      treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
    });

    // アラーム時のアクションとしてSNSを指定
    apiServerErrorAlarm.addAlarmAction(new cwactions.SnsAction(errorTopic));
  }

}

Lambdaのコード

ただエラーとなることが確認できればいいので、Exceptionをraiseするコードをpythonで書きます。 lambdaフォルダを作成し、error-test.pyとして保存します。

./lambda/error-test.py

def handler(event, context):

    raise Exception

試してみる

上記のCDKをデプロイします。

cdk deploy

問題なくデプロイできたら、Lambdaを実行してみます。

当然ですが、raiseしている箇所でエラーとなりました。

少し経つとLambdaがエラーになったのでCloudWatch Alermがアラート状態になり、しかもChatbotで指定したチャンネルへ通知が飛んできました。

単純に連携しただけでここまで綺麗に通知してくれるのは嬉しいですね。 しかもChatbotはこれだけじゃありません。

先ほどの通知にShow logsShow error logsというボタンがあるので、こちらを押してみましょう。ひとまずShow logsを押してみます。

すると、数秒後にはアラートが発生した時間を元にCloudWatch Logsから該当するログをSlackに出力してくれます!すごい!

試しにShow error logsも押してみると、エラー分のみを抽出してコメントしてくれました。

エラーが発生した際にわざわざCloudWatch Logsから探さずにボタン一つでログが見れるのとっても便利ですよね。障害が発生した際、Lambdaのエラーログを即時に確認できるのは調査が捗りそうです。

実はこの機能を利用するためにChatbotのIAMロールにCloudWatch Logsのマネージドポリシーを追加していました。

    chatbotRole.addManagedPolicy(
      iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchLogsReadOnlyAccess')
    );

これがCloudWatch AlermからSNS、Chatbotを連携しただけで利用できるのは感動。Chatbot便利すぎる。

終わりに

障害点が少ない方法でエラーが通知できたら嬉しいなと思い、Chatbotを経由する形で実装してみました。

想像以上に簡単に実装できますし、エラー検知後のログ確認もSlack上で完結するのはとっても便利です。

Lambdaに限らずCloudWatch Alermを利用してエラーが通知したい場合は利用できると思うので、ぜひ活用してみてください。

参考