Docs » Splunk Observability Cloud でサポートされているインテグレーション » バックエンドアプリケーションをインストルメンテーションして、スパンを Splunk APM に送信する » Splunk Observability Cloud けに Go アプリケーションをインストルメンテーションする » Splunk Observability Cloud のログと Go トレースデータを接続する

Splunk Observability Cloud のログと Go トレースデータを接続する 🔗

Splunk OTel Go インストルメンテーションによって自動的に提供されるトレース属性を含めるように、ロギングライブラリを設定できます。トレースメタデータを使用して、トレースとログイベントを関連付け、Splunk でログを調査します。

以下のステップでは、トレースメタデータを抽出し、ログフィールドとしてデータを含むようにロギングライブラリを設定する方法を説明します。

コンテキストからトレースメタデータを抽出する 🔗

OpenTelemetry Trace API の SpanContextFromContext 関数は、トレースメタデータを context.Context から抽出し、SpanContext の形式で返します:

spanContext := trace.SpanContextFromContext(ctx)
if !spanContext.IsValid() {
        // ctx does not contain a valid span.
        // There is no trace metadata to add.
        return
}

SpanContext 構造体は、トレースとスパンID、サンプリング情報を含むトレースフラグ、および状態情報を含みます。このメタデータをログイベントに追加することで、そのコンテキストを充実させ、トレースとログを相関させることができます。

ログイベントに注釈を付ける 🔗

SpanContext でメタデータを収集した後、それを使ってログイベントに注釈を付けることができます。

構造化ログ 🔗

構造化ロガーを使用している場合、トレースメタデータをフィールドとして追加します。次の例は、zap ロギングライブラリを使用してログイベントに注釈を付ける方法を示しています:

logger, _ := zap.NewProduction()
defer logger.Sync()
logger = logger.With(
        zap.String("trace_id", spanContext.TraceID().String()),
        zap.String("span_id", spanContext.SpanID().String()),
        zap.String("trace_flags", spanContext.TraceFlags().String()),
)
logger.Info("Failed to fetch URL", zap.String("URL", url))

非構造化ログ 🔗

非構造化ロギングを使用している場合、ログメッセージの一部としてトレースメタデータを追加することができます。以下の例は、標準ライブラリ log パッケージを使用してトレースメタデータを追加する方法を示しています:

// Add the metadata following an order you can parse later on
log.Printf(
        "(trace_id: %s, span_id: %s, trace_flags: %s): failed to fetch URL: %s",
        spanContext.TraceID().String(),
        spanContext.SpanID().String(),
        spanContext.TraceFlags().String(),
        url,
)

ログ注釈の例 🔗

以下は、トレースメタデータを抽出し、処理されたリクエストのログメッセージに注釈を付ける chi サーバーの完全な例です:

package main

import (
        "context"
        "net/http"

        "github.com/go-chi/chi"
        "github.com/signalfx/splunk-otel-go/instrumentation/github.com/go-chi/chi/splunkchi"
        "go.opentelemetry.io/otel/trace"
        "go.uber.org/zap"
)

func withTraceMetadata(ctx context.Context, logger *zap.Logger) *zap.Logger {
        spanContext := trace.SpanContextFromContext(ctx)
        if !spanContext.IsValid() {
                // ctx does not contain a valid span.
                // There is no trace metadata to add.
                return logger
        }
        return logger.With(
                zap.String("trace_id", spanContext.TraceID().String()),
                zap.String("span_id", spanContext.SpanID().String()),
                zap.String("trace_flags", spanContext.TraceFlags().String()),
        )
}

func helloHandler(logger *zap.Logger) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
                l := withTraceMetadata(r.Context(), logger)

                n, err := w.Write([]byte("Hello World!\n"))
                if err != nil {
                        w.WriteHeader(http.StatusInternalServerError)
                        l.Error("failed to write request response", zap.Error(err))
                } else {
                        l.Info("request handled", zap.Int("response_bytes", n))
                }
        }
}

func main() {
        logger, err := zap.NewProduction()
        if err != nil {
                panic(err)
        }
        defer logger.Sync()

        router := chi.NewRouter()
        router.Use(splunkchi.Middleware())
        router.Get("/hello", helloHandler(logger))
        if err := http.ListenAndServe(":8080", router); err != nil {
                panic(err)
        }
}

This page was last updated on 2023年06月16日.