LoginSignup
5
0

More than 1 year has passed since last update.

運用中のAPIでエラーが出たときどうやって検知してSlackに通知しよう 〜実装編〜

Last updated at Posted at 2022-12-12

はじめに

これは KWC Advent Calendar 2022 の記事です。

はじめまして、KWCに新卒で入社して、バックエンドエンジニアをしているユウスケと申します。
テックブログは初めてです!

*紹介*
昨日の記事で運用中のAPIでエラーが出たときどうやって検知してSlackに通知しよう 〜概要編〜 の続きとなりますので、先に概要編を読むことをおすすめします!

目次

  1. 概要編をサクッとおさらい
  2. システムの構成
  3. いざ実装へ
  4. まとめ

概要編をサクッとおさらい

今回やりたいことは、エラー出た際にSlackへログを通知することです。

Slackへのメッセージ送信の機能の実装場所はプログラム内部に組み込むか、外部に実装する方法の2つあります。詳しくは概要編で!
今回は、外部に実装する方法を話していきます!

システムの構成

システム構成図は以下のようになります。

  1. APIのログはCloudWatch Logsに溜まっていきます
  2. CloudWatch Logsでは、Subscription filterを使い特定の文字が含まれるログを検知します
    1. 今回は_SLACK_NOTIFYをトリガーにしています
  3. 特定の文字があった場合は、そのログがeventとしてLambdaへ送られるようにしています
  4. Lambdaの中でeventの中身を見て、必要な処理をしてからSlackにメッセージを送信します

いざ実装へ

サブスクリプションフィルターで検知するログの作成

サブスクリプションフィルターで検知する_SLACK_NOTIFYを含んだログを出力します。

今回は下のようなログを出力します。

ログの例
2022/12/12 11:12:44 ERROR_SLACK_NOTIFY: エラーメッセージ

サブスクリプションフィルターの設定

Cloud Watchのコンソール画面から、設定したいロググループへ移動して、サブスクリプションフィルターの設定を行います。

Lambda サブスクリプションフィルターを作成では以下の情報を入力します。

送信先を選択

  • 送信したいLambdaを選択します
    (作成済みのLambdaが表示されます)

ログ形式とフィルターを設定

項目 内容
ログの形式 その他
フィルターパターン _SLACK_NOTIFY
フィルター名 任意の名前

これでCloud Watch Logsへ_SLACK_NOTIFYのログが出力された時、サブスクリプションフィルターが起動して、Lambdaが起動します。

Slackへメッセージ送信

メッセージ取り出し

サブスクリプションフィルターから次のようなeventがLambdaへ渡されます。

{
    "owner": "<aws account>",
    "logGroup": "XXXXXXXXXXXXXXXX",
    "logStream": "XXXXXXXXXXXXXXX",
    "subscriptionFilters": [
        "設定したフィルター名"
    ],
    "messageType": "DATA_MESSAGE",
    "logEvents": [
        {
            "id": "3720074778603986400000000000000",
            "timestamp": 1668139223818,
            "message": "ERROR_SLACK_NOTIFY: エラーメッセージ"
        }
    ]
}

次のコードはeventからログを取り出している例です。

func HandleRequest(ctx context.Context, event events.CloudwatchLogsEvent) (string, error) {
	e, _ := event.AWSLogs.Parse() // サブスクリプションフィルターから渡されたeventをパース
	message := e.LogEvents[0].Message
    fmt.Println(message)
    
	return "", nil
}
全体のコード(APIのログを取り出す例)
package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func HandleRequest(ctx context.Context, event events.CloudwatchLogsEvent) (string, error) {
	e, _ := event.AWSLogs.Parse()
	message := e.LogEvents[0].Message
    fmt.Println(message)
    
	return "", nil
}

func main() {
	lambda.Start(HandleRequest)
}

Slackへメッセージを送る関数作成

SlackのSDKを使い、Slackへメッセージを送信します。

func SendMessage(message string) {
	c := slack.New(os.Getenv("SLACK_TOKEN"))

	_, _, err := c.PostMessage(os.Getenv("POST_CHANNEL"), slack.MsgOptionBlocks(
		&slack.SectionBlock{
			Type: slack.MBTSection,
			Text: &slack.TextBlockObject{
				Type: "mrkdwn",
				Text: message,
			},
		},
	))
	if err != nil {
		panic(err)
	}
}

この関数の引数に、イベントから取得したログを渡してSlackへ通知することができます。

完成したコード
main.go
package main

import (
	"context"
	"os"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/slack-go/slack"
)

func SendMessage(message string) {
	c := slack.New(os.Getenv("SLACK_TOKEN"))

	_, _, err := c.PostMessage(os.Getenv("POST_CHANNEL"), slack.MsgOptionBlocks(
		&slack.SectionBlock{
			Type: slack.MBTSection,
			Text: &slack.TextBlockObject{
				Type: "mrkdwn",
				Text: message,
			},
		},
	))
	if err != nil {
		panic(err)
	}
}

func HandleRequest(ctx context.Context, event events.CloudwatchLogsEvent) (string, error) {
	e, _ := event.AWSLogs.Parse()
	message := e.LogEvents[0].Message

	SendMessage(message)

	return "", nil
}

func main() {
	lambda.Start(HandleRequest)
}

まとめ

アプリが出した特定のログを検知してSlackへ通知する方法を紹介しました。
これは一例なので環境にあった実装を試してみてください!

宣伝

KWC Advent Calendar 2022はまだまだ、続きますので良ければ他の記事もご覧ください!!

5
0
0

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
  3. You can use dark theme
What you can do with signing up
5
0