😆

frontendのエラーをSlack通知したい

2021/02/28に公開

概要

frontendで起きたエラーを、Sentryを使ってSlack通知していきます。

Sentry公式が用意しているSlack IntegrationはSentryの有料プランじゃないと使えないので、
SentryのWebhook、AWS Lamba、API Gateway、SlackのIncomming Webhookを組み合わせ、無料プランで実現していきます。

経緯

frontendのエラーログ監視に「Sentry」を使用することにしました。

以下のコードをエントリーポイントに仕込めば、

import * as Sentry from '@sentry/browser'
import { Integrations } from '@sentry/tracing'

Sentry.init({
  dsn: 'https://xxxx',
  integrations: [new Integrations.BrowserTracing()],
  tracesSampleRate: 1.0,
})

以下のように、エラーが起きたときSentryのWebUI上で確認することができます。

deviceの情報・osの情報なども自動で取得してくれるので、特にfrontendでのエラー監視に便利だと感じています。

これだけでも最高なのですが、Sentryは様々なサービスとのintegrationが可能です。

今回、Slackと連携することにより、Sentryで捕まえたエラーログをSlackに通知したいと思ったのですが、、、

SentryのTeamプランが必要でした。そしてTeamプランは有料。

諦めかけましたが、Webhookは無料プラン(Developer Plan)でも使用できるようです。

今回、Webhookを使用して、無料プランでもSlack通知できるようにしてみました。

目的

Slackに、こんな感じの通知が来るようにします。

構成

AWS Lambdaを用います。

Sentry上でログを検出したら、Sentry WebHooksからAPI Gatewayで作成したエンドポイントを叩き、Lambdaを呼び出します。

LambdaからSlackのIncomming Webhookを叩いてSlackに通知します。

手順

  1. SlackのIncomming Webhookの設定
    設定方法はこちら

  2. AWS Lambdaで関数の作成

    今回はnode.jsで作成しました。

    event.bodyでSentryからやってくるjsonにアクセスできます。

    Sentry公式にもjson構造はのっていますが、若干実際の構造とずれているので試行錯誤して確かめました。

    const { IncomingWebhook } = require('@slack/webhook')
    // Webhook url
    const url = 'https://hooks.slack.com/xxxxx'
    const webhook = new IncomingWebhook(url)
    
    exports.handler = async (event) => {
      const sentryBodyStr = event.body
      const sentryBody = JSON.parse(sentryBodyStr)
      const sentryEvent = sentryBody.event
      
      // ブラウザ情報
      const browserInfo = (() => {
        const browser = sentryEvent.contexts.browser
        if (browser === undefined) return 'unknown'
        return `${browser.name} ${browser.type} ${browser.version}`
      })()
      
      // OS情報
      const osInfo = (() => {
        const os = sentryEvent.contexts.os
        if (os === undefined) return 'unknown'
        return `${os.name} ${os.type} ${os.version}`
      })()
      
      // デバイス情報
      const deviceInfo = (() => {
        const device = sentryEvent.contexts.device
        if (device === undefined) return 'unknown'
        return `${device.family}`
      })()
      
      // エラー名
      const title = sentryEvent.title
      
      // Sentryのissue URL
      const url = sentryBody.url
      
      // 環境
      const env = sentryEvent.environment
    
      const issue = {
        message: title,
        detail: url,
        browser: browserInfo,
        os: osInfo,
        device: deviceInfo
      }
      const issueProperties = Object.entries(issue).map(entry => { return `${entry[0]}: ${entry[1]}` })
    
      const payload = {
        "blocks": [
          {
    	"type": "section",
    	"text": {
    	  "type": "mrkdwn",
    	  "text": `:ghost: *${env}* でエラーがおきたよ`
    	}
          },
          {
    	"type": "section",
    	"text": {
    	  "type": "mrkdwn",
    	  "text": issueProperties.join('\n')
    	}
          },
        ]
      }
      await webhook.send(payload)
    }
    
  3. AWS API GatewayをトリガにしてAWS Lambdaが動作するよう設定する
    設定方法はこちら

  4. SentryのWebHooksにAPI Gatewayのendpointを指定する

    Setting > Integrations > WebhooksそしてAdd To Projectを選択し、

    API Gatewayのendpointを設定します。

  5. SentryのAlert設定で、どういう条件のときにwebhookをkickするか設定を行う

これで設定は終了です。

無事、Sentryで検出したエラーがSlackに来るようになりました。

まとめ

SentryがWebhookという汎用性の高い手段を提供してくれているので、助かりました。

これでfrontendのエラー検知が捗りそうです。

Discussion