Querier

Cloud Loggingで収集したログをCloud Pub/SubとCloud Functionsを使ってSlackに通知する

2022.08.22に公開 | 2022.08.22に更新

Querier運営

@querier_io@querierinc

「Querier(クエリア)」は社内向け管理画面を圧倒的な速さで、かつビジネスのスケールに合わせて柔軟に構築することができるローコードツールです。

管理画面の構築もWeb上で完結
エンジニアのためのローコードツール

Querierについて詳しく見る

みなさんこんにちは、Querier開発チームです。
アプリケーションのエラーを監視したいという要件はどの開発チームでもあると思います。
今回は、

Cloud Logging → ログルーター → Cloud Pub/Sub → Cloud Functions → Slack

という構成でCloud LoggingのエラーログをSlackに通知してみます。

Cloud Loggingでログを収集する

Zapdriverを使うと、Cloud Loggingに最適化したログを残してくれます。

package main

import (
	"log"
	"runtime"

	"github.com/blendle/zapdriver"
	"go.uber.org/zap"
)

var l *zap.Logger

// Zapdriverを使ってLoggerを初期化する
func init() {
	var err error
	l, err = zapdriver.NewProductionWithCore(zapdriver.WrapCore(
		zapdriver.ServiceName("<app_name>"), // 任意のアプリケーション名
	))
	if err != nil {
		log.Fatal(err)
	}
}

// ログを残す
func main() {
	err := fn()
	if err != nil {
		l.Error(
			err.Error(),
			zapdriver.ErrorReport(runtime.Caller(0)),
		)
	}
}

Cloud Loggingのログルーターを介してCloud Pub/Subにシンクする

① GCPコンソールの左タブの「ロギング」→「ログルーター」に行きます。
② 「シンクを作成」を押します。
③ 「シンク名」を入力します。
④ 「シンクの宛先」は「Cloud Pub/Sub トピック」を、「Cloud Pub/Sub トピックを選択」は「新しい Cloud Pub/Sub トピックを作成する」を選択し、新しいトピックを作成します。
⑤ 「シンクに含めるログの選択」では、任意のフィルタを記述します。例として、Cloud Runのエラーログのみを通知する例を下に記しておきます。

severity=ERROR
resource.type="cloud_run_revision"

⑥ 4は一旦省略でOKです

これで、フィルタにマッチするログを認識してCloud Pub/Subのトピックにパブリッシュされます。
以上でログルーターの設定は終了です。また、Cloud Pub/Sub側の設定も特段必要ありません。

Cloud Functionsの関数を記述する

今回はGoで関数を記述してみます。

package function

import (
	"context"
	"encoding/json"

	"github.com/slack-go/slack"
)

// ログルータを介してパブリッシュされたデータが入ってくる構造体
type PubSubMessage struct {
	Data []byte `json:"data"`
}

// Cloud Loggingで収集するデータ構造をGoの構造体として定義する
type ErrLog struct {
	InsertID string `json:"insertId"`
	Resource struct {
		Type   string `json:"type"`
		Labels struct {
			ServiceName       string `json:"service_name"`
			ProjectID         string `json:"project_id"`
			Location          string `json:"location"`
			RevisionName      string `json:"revision_name"`
			ConfigurationName string `json:"configuration_name"`
		} `json:"labels"`
	} `json:"resource"`
	Timestamp string `json:"timestamp"`
	Severity  string `json:"severity"`
	Labels    struct {
		InstanceID string `json:"instanceId"`
	} `json:"labels"`
	LogName          string `json:"logName"`
	ReceiveTimestamp string `json:"receiveTimestamp"`
	JSONPayload struct {
		Timestamp      string `json:"timestamp"`
		Stacktrace     string `json:"stacktrace"`
		Caller         string `json:"caller"`
		ServiceContext struct {
			Service string `json:"service"`
		} `json:"serviceContext"`
		Message string `json:"message"`
	} `json:"jsonPayload"`
	Context struct {
		ReportLocation struct {
			FilePath     string `json:"filePath"`
			FunctionName string `json:"functionName"`
			LineNumber   string `json:"lineNumber"`
		} `json:"reportLocation"`
	} `json:"context"`
	SourceLocation struct {
		File     string `json:"file"`
		Line     string `json:"line"`
		Function string `json:"function"`
	} `json:"sourceLocation"`
}

const webhookURL = ""

func Fn(ctx context.Context, m PubSubMessage) error {
	l := &ErrLog{}
	if err := json.Unmarshal(m.Data, l); err != nil {
		return err
	}

	return slack.PostWebhook(webhookURL, &slack.WebhookMessage{
		Username: "<user_name>",
		Channel:  "<channel_name>",
		Text:  l.JSONPayload.Message,
		Attachments: []slack.Attachment{
			{
				Color: "danger",
				Fields: []slack.AttachmentField{
					{
						Title: "ProjectID",
						Value: l.Resource.Labels.ProjectID,
					},
					{
						Title: "Service",
						Value: l.Resource.Labels.ServiceName,
					},
					{
						Title: "Severity",
						Value: l.Severity,
					},
					{
						Title: "Timestamp",
						Value: l.JSONPayload.Timestamp,
					},
					{
						Title: "Stacktrace",
						Value: l.JSONPayload.Stacktrace,
					},
				},
			},
		},
	})
}

Cloud Buildを使って関数をデプロイする

steps:
- name: 'gcr.io/cloud-builders/gcloud'
  args:
  - functions
  - deploy
  - <Cloud Functionsの名前>
  - --runtime
  - go116
  - --region
  - asia-northeast1
  - --entry-point
  - Fn
  - --trigger-topic
  - <Cloud Pub/Subのトピック名>

以上でエラーログを収集し、Slackに通知をするセッティングは完了です。
Cloud Loggingのみでは、Slackに通知することができず、GCP内の複数のサービスを使うことによって実現することができます。
複数サービスを連携しなければいけないので一見複雑そうに見えますが、それぞれのサービスではそこまで難しいことはやっていないので、ぜひやってみてください!

「Querier(クエリア)」は社内向け管理画面を圧倒的な速さで、かつビジネスのスケールに合わせて柔軟に構築することができるローコードツールです。

最新の記事

【告知】値の参照時の仕様変更のお知らせ

このたび2024年11月11日に値の参照に関する仕様変更を予定しておりますので詳細について報告いたします。

more

管理画面の構築もWeb上で完結
エンジニアのためのローコードツール

Querierについて詳しく見る