🔭

トレーススパンを用いたデバッグ情報の可視化

2025/01/31に公開

はじめに

Observability を向上させるのに必要不可欠なトレースを用いてより効率的にシステムの状態を可視化するための設定を紹介します。

前提

実装は OpenTelemetry を利用しています。
トレースバックエンドとしては Google Cloud の Cloud Trace を利用しています。

共通実装

詳細は省略しますが、トレースを吐き出すための準備として以下のようなコードを実装しています。

package main

import (
	"context"

	texporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
	"google.golang.org/api/option"
)

func main() {
	exporter, err := texporter.New(
		texporter.WithProjectID(""), // 置き換え
		texporter.WithTraceClientOptions(
			[]option.ClientOption{
				// https://github.com/gcpug/nouhau/issues/149
				option.WithTelemetryDisabled(),
			},
		),
	)
	if err != nil {
		panic(err)
	}
	defer exporter.Shutdown(context.Background())

	ctx := context.Background()

	rs, err := resource.New(
		ctx,
		resource.WithAttributes(
			semconv.ServiceNameKey.String("trace"),
		),
	)
	if err != nil {
		panic(err)
	}

	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exporter),
		sdktrace.WithResource(rs),
	)
	defer tp.Shutdown(context.Background())

	otel.SetTracerProvider(tp)
}

トレースの活用

通常利用

まずは特に意識せずに以下のようにスパンを吐き出します。

ctx, span := otel.Tracer("main").Start(ctx, "main")
defer span.End()

_, span1 := otel.Tracer("main").Start(ctx, "sub1")
defer span1.End()

シンプルな 2 つのスパンが繋がっているトレースが可視化されます。

SetStatus

import (
	"go.opentelemetry.io/otel/codes"
)

func main() {
    ...
	_, span1 := otel.Tracer("main").Start(ctx, "sub1")
+	span1.SetStatus(codes.Error, "status error")
	defer span1.End()
}

Cloud Trace の UI 上において、トレースの詳細画面では特に変化はありません。

一覧画面ではスパンのステータスがエラーになっていることが確認できます。

RecordError

func main() {
    ...
+	span1.RecordError(fmt.Errorf("record error"))
	defer span1.End()
}

スパンの ログとイベント タブにイベントが追加されます。

AddEvent

func main() {
    ...
+	span1.AddEvent("event1")
	defer span1.End()
}

RecordError と同様にスパンの ログとイベント タブにイベントが追加されます。

これは RecordErrorAddEvent は内部で付与される attribute が異なるだけで最終的には addEvent を呼び出しているため挙動としては同じ挙動になります。

https://github.com/open-telemetry/opentelemetry-go/blob/a81250ca3e5daac8962cc41862e7cfdf3ceb4454/sdk/trace/span.go#L522

https://github.com/open-telemetry/opentelemetry-go/blob/a81250ca3e5daac8962cc41862e7cfdf3ceb4454/sdk/trace/span.go#L566

Discussion