使用 OpenTelemetry 管理观测类数据

官方文档:https://opentelemetry.io/docs/instrumentation/go/getting-started/

Trace API

通过 Trace API 生成 traces。

package main

import (
	"context"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
)

func f1(ctx context.Context, v string) {
    ctx, span = otel.Tracer("tracer_name").Start(ctx, "trace_name")
    span.SetAttributes(attribute.String("f1.v", v))
    defer span.End()
    
    if err := f2(ctx); err != nil {
        span.RecordError(err)
        span.SetStatus(codes.Error, err.Error())
    }
}

Exporter

Exporter 将生成的 traces 导出到 Jaeger, Zipkin, 和 Prometheus 等位置.
https://pkg.go.dev/go.opentelemetry.io/otel/exporters
也可以通过 io.Writer 导出到自定义的文件,控制台。

package main

import (
	"io"

	"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
	"go.opentelemetry.io/otel/sdk/trace"
)

// newExporter returns a console exporter.
func newExporter(w io.Writer) (trace.SpanExporter, error) {
	return stdouttrace.New(
		stdouttrace.WithWriter(w),
		// Use human-readable output.
		stdouttrace.WithPrettyPrint(),
		// Do not print timestamps for the demo.
		stdouttrace.WithoutTimestamps(),
	)
}

Resource

Resource 用于将程序(服务)本身声明为 OpenTelemetry 可以理解的一个资源,以使接收这些 traces 的一方能知道数据的来源。

package main

import (
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/sdk/resource"
	semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
)

// newResource returns a resource describing this application.
func newResource() *resource.Resource {
	r, _ := resource.Merge(
		resource.Default(),
		resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceNameKey.String("fib"),
			semconv.ServiceVersionKey.String("v0.1.0"),
			attribute.String("environment", "demo"),
		),
	)
	return r
}

Tracer Provider

上面使用 Trace API 时,otel.Tracer 内部通过一个 GetTracerProvider 函数获取 TracerProvider,然后再生成 Tracer,我们需要将自定义的 TraceProvider 进行安装,使调用 GetTracerProvider 函数时取到自定义的 TraceProvider。

package main

import (
	"context"
	"log"
	"os"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/sdk/trace"
)

func main() {
	ctx := context.Background()
	l := log.New(os.Stdout, "", 0)

	// Write telemetry data to a file.
	f, err := os.Create("traces.txt")
	if err != nil {
		l.Fatal(err)
	}
	defer f.Close()
	exp, err := newExporter(f)
	if err != nil {
		l.Fatal(err)
	}
	tp := trace.NewTracerProvider(
		trace.WithBatcher(exp),
		trace.WithResource(newResource()),
	)
	defer func() {
		if err = tp.Shutdown(ctx); err != nil {
			l.Fatal(err)
		}
	}()
	otel.SetTracerProvider(tp)

    f1(ctx, "test")
}

实例化 TracerProvider 需要 Exporter 和 Resource 作为参数,最后通过 otel.SetTracerProvider(tp) 安装自定义的 TracerProvider。


版权声明:本文为aimeimeiTS原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。