以OpenTelemetry方式接入 在监控Go应用之前,您需要通过客户端将应用数据上报至APM服务端。本文介绍如何通过OpenTelemetry Go SDK上报Go应用数据。 前提条件 完成vpce接入。 背景信息 OpenTelemetry Go SDK提供了Go语言的分布式链路追踪能力,您可以直接使用OTLP gRPC或者HTTP协议向APM服务端上报数据。 接入步骤 1. 添加OpenTelemetry Go依赖。 plaintext 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" ) 2. 查看接入点信息。 应用列表的接入指引会根据您所在资源池提供“通过 HTTP 上报数据”和“通过 gRPC 上报数据”的ENDPOINT(天翼云vpc网络接入点)、鉴权TOKEN信息。 3. 初始化OpenTelemetry Go SDK。 (注意需将token和endpoint替换成相应地域的接入点信息。) 注意 需将token和endpoint替换成相应地域的接入点信息。 方式1:使用HTTP协议上报数据。 plaintext func initProvider() func() { ctx : context.Background() auth : map[string]string{ "xctgauthorization": " ", // 替换成token信息 } path : flag.String("path", "/v1/traces", "path") traceClient : otlptracehttp.NewClient( otlptracehttp.WithEndpoint(" "), // 替换成otel http的上报地址。 otlptracehttp.WithURLPath(path), otlptracehttp.WithHeaders(auth), otlptracehttp.WithInsecure()) otlptracehttp.WithCompression(1) 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( // 在APM控制台显示的服务名称。 semconv.ServiceNameKey.String("otelgoclientdemo"), // 在APM控制台显示的主机名称。 semconv.HostNameKey.String("yourhostname"), // 在APM控制台显示的服务端地址。 semconv.NetSockHostAddr("serviceaddr"), // 在APM控制台显示的客户端地址。 semconv.NetSockPeerAddr("clientaddr"), ), ) 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) } } } 方式2:使用gRPC协议上报数据。 plaintext func initProviderGrpc() func() { ctx : context.Background() auth : map[string]string{ "xctgauthorization": " ", //接入流程里面获取token信息 } traceClient : otlptracegrpc.NewClient( otlptracegrpc.WithInsecure(), otlptracegrpc.WithEndpoint(" "), //替换成grpc接入信息 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( // 在APM控制台显示的服务名称。 semconv.ServiceNameKey.String("otelgoclientdemoprovider"), // 在APM控制台显示的主机名称。 semconv.HostNameKey.String("yourhostname"), // 在APM控制台显示的服务端地址。 semconv.NetSockHostAddr("serviceaddr"), // 在APM控制台显示的客户端地址。 semconv.NetSockPeerAddr("clientaddr"), ), ) 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) } } } 4. client端上报例子。 plaintext func sendReq(url string, ctx context.Context) { // 构造一个trace client client : http.Client{ Transport: otelhttp.NewTransport( http.DefaultTransport, 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", " "server url") flag.Parse() bag, : baggage.Parse("usernamexxx") ctx : baggage.ContextWithBaggage(context.Background(), bag) doClient(url, ctx) } 5. 服务端上报例子。 plaintext func handler() { uk : attribute.Key("username") //加点属性 helloHandler : func(w http.ResponseWriter, req http.Request) { ctx : req.Context() //继续调用下一个服务最终效果是client》hello》hello1 sendReq(" 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) } } 6. 通过以上步骤,最后就在APM控制台的应用列表页面选择目标应用,查看监控数据。