searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

如何通过otel sdk实现go语言调用链路数据上报

2023-10-30 01:56:16
67
0
  1. 添加OpenTelemetry Go依赖。
package main
import (
	"context"
	"flag"
	"go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace"
	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/baggage"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
	"go.opentelemetry.io/otel/trace"
	"io"
	"log"
	"net/http"
	"net/http/httptrace"
	"time"
)
  1. 初始化OpenTelemetry Go SDK。
func initProvider() func() {
	ctx := context.Background()
	auth := map[string]string{
		"header": "xxx", // 添加header信息
	}
	traceClient := otlptracegrpc.NewClient(
		otlptracegrpc.WithInsecure(),
		otlptracegrpc.WithEndpoint("xxx:port"),    //collector
       otlptracehttp.WithURLPath("/api/traces"),
		otlptracegrpc.WithHeaders(auth),
		otlptracegrpc.WithDialOption(grpc.WithBlock()))
	log.Println("start to connect to server")
	traceExp, err := otlptrace.New(ctx, traceClient)
	handleErr(err, "Failed to create the collector trace exporter")
	res, err := resource.New(ctx,
		resource.WithFromEnv(),
		resource.WithProcess(),
		resource.WithTelemetrySDK(),
		resource.WithHost(),
		resource.WithAttributes(
			// 在可观测链路 OpenTelemetry 版后端显示的服务名称。
			semconv.ServiceNameKey.String("otel-go-client-demo"),
			semconv.HostNameKey.String(""),
		),
	)
	handleErr(err, "failed to create resource")
	bsp := sdktrace.NewBatchSpanProcessor(traceExp)
	tracerProvider := sdktrace.NewTracerProvider(
		sdktrace.WithSampler(sdktrace.AlwaysSample()),
		sdktrace.WithResource(res),
		sdktrace.WithSpanProcessor(bsp),
	)
	otel.SetTracerProvider(tracerProvider)
	return func() {
		cxt, cancel := context.WithTimeout(ctx, time.Second)
		defer cancel()
		if err := traceExp.Shutdown(cxt); err != nil {
			otel.Handle(err)
		}
	}
}

 

  1. client上报例子
func sendReq(url string, ctx context.Context) {
    // 构造一个trace client
	client := http.Client{
		Transport: otelhttp.NewTransport(
			http.DefaultTransport,
                         // 下面这个一定要加不加trace不会透传
			otelhttp.WithClientTrace(func(ctx context.Context) *httptrace.ClientTrace {
				return otelhttptrace.NewClientTrace(ctx)
			}),
		),
	}

	tr := otel.Tracer("example/client")
	err := func(ctx context.Context) error {
		ctx, span := tr.Start(ctx, "say hello", trace.WithAttributes(semconv.PeerService("ExampleService")))
		defer span.End()
		ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx))
		req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
		res, err := client.Do(req)
		if err != nil {
			panic(err)
		}
		_, err = io.ReadAll(res.Body)
		_ = res.Body.Close()
		return err
	}(ctx)

	if err != nil {
		log.Fatal(err)
	}
}

func doClient(url string, ctx context.Context) {
	// 不断请求数据
	for {
		sendReq(url, ctx)
		time.Sleep(3 * time.Second)
	}
}

func main() {
	shutdown := initProvider()
	defer shutdown()
	url := flag.String("server", "localhost:8070/hello", "server url")
	flag.Parse()
	bag, _ := baggage.Parse("username=xxx")
	ctx := baggage.ContextWithBaggage(context.Background(), bag)
	doClient(*url, ctx)
}
  1. 服务端上报例子
func handler() {
	uk := attribute.Key("username") //加点属性

	helloHandler := func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
        //继续调用下一个服务最终效果是client-》hello-》hello1
		sendReq("localhost:8071/hello1", ctx)
	}

	helloHandler1 := func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
		span := trace.SpanFromContext(ctx)
		bag := baggage.FromContext(ctx)
		span.AddEvent("handling this...", trace.WithAttributes(uk.String(bag.Member("username").Value())))
		_, _ = io.WriteString(w, "Hello, world!\n")
	}

	otelHandler := otelhttp.NewHandler(http.HandlerFunc(helloHandler), "Hello")
	otelHandler1 := otelhttp.NewHandler(http.HandlerFunc(helloHandler1), "Hello1")

	http.Handle("/hello", otelHandler)
	http.Handle("/hello1", otelHandler1)
}

func main() {
	flag.Parse()
	shutdown := initProvider()
	defer shutdown()
	handler()
	err := http.ListenAndServe(":" + *serverPort, nil) //nolint:gosec // Ignoring G114: Use of net/http serve function that has no support for setting timeouts.
	if err != nil {
		log.Fatal(err)
	}
}

 

通过以上例子就可以实现a->b->c这种调用链路

0条评论
0 / 1000
李****涛
13文章数
0粉丝数
李****涛
13 文章 | 0 粉丝
原创

如何通过otel sdk实现go语言调用链路数据上报

2023-10-30 01:56:16
67
0
  1. 添加OpenTelemetry Go依赖。
package main
import (
	"context"
	"flag"
	"go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace"
	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/baggage"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
	"go.opentelemetry.io/otel/trace"
	"io"
	"log"
	"net/http"
	"net/http/httptrace"
	"time"
)
  1. 初始化OpenTelemetry Go SDK。
func initProvider() func() {
	ctx := context.Background()
	auth := map[string]string{
		"header": "xxx", // 添加header信息
	}
	traceClient := otlptracegrpc.NewClient(
		otlptracegrpc.WithInsecure(),
		otlptracegrpc.WithEndpoint("xxx:port"),    //collector
       otlptracehttp.WithURLPath("/api/traces"),
		otlptracegrpc.WithHeaders(auth),
		otlptracegrpc.WithDialOption(grpc.WithBlock()))
	log.Println("start to connect to server")
	traceExp, err := otlptrace.New(ctx, traceClient)
	handleErr(err, "Failed to create the collector trace exporter")
	res, err := resource.New(ctx,
		resource.WithFromEnv(),
		resource.WithProcess(),
		resource.WithTelemetrySDK(),
		resource.WithHost(),
		resource.WithAttributes(
			// 在可观测链路 OpenTelemetry 版后端显示的服务名称。
			semconv.ServiceNameKey.String("otel-go-client-demo"),
			semconv.HostNameKey.String(""),
		),
	)
	handleErr(err, "failed to create resource")
	bsp := sdktrace.NewBatchSpanProcessor(traceExp)
	tracerProvider := sdktrace.NewTracerProvider(
		sdktrace.WithSampler(sdktrace.AlwaysSample()),
		sdktrace.WithResource(res),
		sdktrace.WithSpanProcessor(bsp),
	)
	otel.SetTracerProvider(tracerProvider)
	return func() {
		cxt, cancel := context.WithTimeout(ctx, time.Second)
		defer cancel()
		if err := traceExp.Shutdown(cxt); err != nil {
			otel.Handle(err)
		}
	}
}

 

  1. client上报例子
func sendReq(url string, ctx context.Context) {
    // 构造一个trace client
	client := http.Client{
		Transport: otelhttp.NewTransport(
			http.DefaultTransport,
                         // 下面这个一定要加不加trace不会透传
			otelhttp.WithClientTrace(func(ctx context.Context) *httptrace.ClientTrace {
				return otelhttptrace.NewClientTrace(ctx)
			}),
		),
	}

	tr := otel.Tracer("example/client")
	err := func(ctx context.Context) error {
		ctx, span := tr.Start(ctx, "say hello", trace.WithAttributes(semconv.PeerService("ExampleService")))
		defer span.End()
		ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx))
		req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
		res, err := client.Do(req)
		if err != nil {
			panic(err)
		}
		_, err = io.ReadAll(res.Body)
		_ = res.Body.Close()
		return err
	}(ctx)

	if err != nil {
		log.Fatal(err)
	}
}

func doClient(url string, ctx context.Context) {
	// 不断请求数据
	for {
		sendReq(url, ctx)
		time.Sleep(3 * time.Second)
	}
}

func main() {
	shutdown := initProvider()
	defer shutdown()
	url := flag.String("server", "localhost:8070/hello", "server url")
	flag.Parse()
	bag, _ := baggage.Parse("username=xxx")
	ctx := baggage.ContextWithBaggage(context.Background(), bag)
	doClient(*url, ctx)
}
  1. 服务端上报例子
func handler() {
	uk := attribute.Key("username") //加点属性

	helloHandler := func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
        //继续调用下一个服务最终效果是client-》hello-》hello1
		sendReq("localhost:8071/hello1", ctx)
	}

	helloHandler1 := func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
		span := trace.SpanFromContext(ctx)
		bag := baggage.FromContext(ctx)
		span.AddEvent("handling this...", trace.WithAttributes(uk.String(bag.Member("username").Value())))
		_, _ = io.WriteString(w, "Hello, world!\n")
	}

	otelHandler := otelhttp.NewHandler(http.HandlerFunc(helloHandler), "Hello")
	otelHandler1 := otelhttp.NewHandler(http.HandlerFunc(helloHandler1), "Hello1")

	http.Handle("/hello", otelHandler)
	http.Handle("/hello1", otelHandler1)
}

func main() {
	flag.Parse()
	shutdown := initProvider()
	defer shutdown()
	handler()
	err := http.ListenAndServe(":" + *serverPort, nil) //nolint:gosec // Ignoring G114: Use of net/http serve function that has no support for setting timeouts.
	if err != nil {
		log.Fatal(err)
	}
}

 

通过以上例子就可以实现a->b->c这种调用链路

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0