通過(guò)OpenTelemetry上報(bào)Go應(yīng)用數(shù)據(jù)
通過(guò)OpenTelemetry為應(yīng)用埋點(diǎn)并上報(bào)鏈路數(shù)據(jù)至可觀測(cè)鏈路 OpenTelemetry 版后,可觀測(cè)鏈路 OpenTelemetry 版即可開(kāi)始監(jiān)控應(yīng)用,您可以查看應(yīng)用拓?fù)洹⒄{(diào)用鏈路、異常事務(wù)、慢事務(wù)和SQL分析等一系列監(jiān)控?cái)?shù)據(jù)。本文介紹如何使用OpenTelemetry Go SDK進(jìn)行手動(dòng)埋點(diǎn)并上報(bào)數(shù)據(jù)。
ARMS應(yīng)用監(jiān)控針對(duì)Golang語(yǔ)言提供了商業(yè)化版本的自研探針,提供了無(wú)侵入的埋點(diǎn)能力,擁有更加豐富的功能和更高的穩(wěn)定性。詳細(xì)信息,請(qǐng)參見(jiàn)開(kāi)始監(jiān)控Golang應(yīng)用。
前提條件
登錄ARMS控制臺(tái),在左側(cè)導(dǎo)航欄單擊接入中心。
在服務(wù)端應(yīng)用區(qū)域單擊OpenTelemetry卡片。
在彈出的OpenTelemetry面板中選擇數(shù)據(jù)需要上報(bào)的地域。
說(shuō)明初次接入的地域?qū)?huì)自動(dòng)進(jìn)行資源初始化。
選擇連接方式和上報(bào)方式,然后復(fù)制接入點(diǎn)信息。
連接方式:若您的服務(wù)部署在阿里云上,且所屬地域與選擇的接入地域一致,推薦使用阿里云內(nèi)網(wǎng)方式,否則選擇公網(wǎng)方式。
上報(bào)方式:根據(jù)客戶端支持的協(xié)議類(lèi)型選擇HTTP或gRPC協(xié)議上報(bào)數(shù)據(jù)。
背景信息
OpenTelemetry Go SDK提供了Go語(yǔ)言的分布式鏈路追蹤能力,您可以直接使用OTLP gRPC或者HTTP協(xié)議向鏈路追蹤服務(wù)端上報(bào)數(shù)據(jù)。
OpenTelemetry提供了若干半自動(dòng)埋點(diǎn)插件(無(wú)需手動(dòng)創(chuàng)建Span,只需要在代碼中使用這些插件提供的API),支持為常見(jiàn)的框架自動(dòng)創(chuàng)建Span。支持的框架列表請(qǐng)參見(jiàn)OpenTelemetry官方文檔。
示例Demo
使用gRPC協(xié)議上報(bào)
添加OpenTelemetry Go依賴。
go get go.opentelemetry.io/otel go get go.opentelemetry.io/otel/trace go get go.opentelemetry.io/otel/sdk go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc // otlp grpc
初始化OpenTelemetry Go SDK。
您可以選擇通過(guò)OpenTelemetry SDK直接上報(bào)或通過(guò)開(kāi)源OpenTelemetry Collector轉(zhuǎn)發(fā)。
如果選擇直接上報(bào),請(qǐng)將otelAgentAddr和xtraceToken替換為前提條件獲取的接入點(diǎn)和鑒權(quán)Token。
如果選擇使用OpenTelemetry Collector轉(zhuǎn)發(fā),請(qǐng)將otelAgentAddr替換為您本地部署的服務(wù)地址,并刪除Header信息。
func initProvider() func() { ctx := context.Background() otelAgentAddr, xtraceToken, ok := common.ObtainXTraceInfo() if !ok { log.Fatalf("Cannot init OpenTelemetry, exit") os.Exit(-1) } headers := map[string]string{"Authentication": xtraceToken} //將xtraceToken替換為前提條件中獲取的鑒權(quán)Token。 traceClient := otlptracegrpc.NewClient( otlptracegrpc.WithInsecure(), otlptracegrpc.WithEndpoint(otelAgentAddr), //將otelAgentAddr替換為前提條件中獲取的接入點(diǎn)。 otlptracegrpc.WithHeaders(headers), 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( // 在可觀測(cè)鏈路 OpenTelemetry 版后端顯示的服務(wù)名稱(chēng)。 semconv.ServiceNameKey.String(common.ServerServiceName), semconv.HostNameKey.String(common.ServerServiceHostName), ), ) handleErr(err, "failed to create resource") bsp := sdktrace.NewBatchSpanProcessor(traceExp) tracerProvider := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithResource(res), sdktrace.WithSpanProcessor(bsp), ) // 設(shè)置全局propagator為tracecontext(默認(rèn)不設(shè)置)。 otel.SetTextMapPropagator(propagation.TraceContext{}) otel.SetTracerProvider(tracerProvider) return func() { cxt, cancel := context.WithTimeout(ctx, time.Second) defer cancel() if err := traceExp.Shutdown(cxt); err != nil { otel.Handle(err) } } }
添加埋點(diǎn)。
shutdown := initProvider() defer shutdown() //meter := global.Meter("demo-server-meter") serverAttribute := attribute.String("server-attribute", "foo") fmt.Println("start to gen chars for trace data") initTraceDemoData() fmt.Println("gen trace data done") tracer := otel.Tracer(common.TraceInstrumentationName) // 在OpenTelemetry中創(chuàng)建一個(gè)handler。 handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { // 模擬延遲 var sleep int64 switch modulus := time.Now().Unix() % 5; modulus { case 0: sleep = rng.Int63n(2000) case 1: sleep = rng.Int63n(15) case 2: sleep = rng.Int63n(917) case 3: sleep = rng.Int63n(87) case 4: sleep = rng.Int63n(1173) } ctx := req.Context() span := trace.SpanFromContext(ctx) span.SetAttributes(serverAttribute) actionChild(tracer, ctx, sleep) w.Write([]byte("Hello World")) }) wrappedHandler := otelhttp.NewHandler(handler, "/hello") http.Handle("/hello", wrappedHandler) http.ListenAndServe(":7080", nil)
啟動(dòng)應(yīng)用程序。
go run main.go
登錄ARMS控制臺(tái)后,在 頁(yè)面選擇目標(biāo)應(yīng)用,查看鏈路數(shù)據(jù)。
說(shuō)明語(yǔ)言列顯示圖標(biāo)的應(yīng)用為接入應(yīng)用監(jiān)控的應(yīng)用,顯示-圖標(biāo)的應(yīng)用為接入可觀測(cè)鏈路 OpenTelemetry 版的應(yīng)用。
使用HTTP協(xié)議上報(bào)
添加OpenTelemetry Go依賴。
go get go.opentelemetry.io/otel go get go.opentelemetry.io/otel/trace go get go.opentelemetry.io/otel/sdk go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp // otlp http
初始化OpenTelemetry Go SDK,其中Endpoint和URLPath需替換為前提條件中獲取的接入點(diǎn)信息。
您可以選擇通過(guò)OpenTelemetry SDK直接上報(bào)或通過(guò)開(kāi)源OpenTelemetry Collector轉(zhuǎn)發(fā)。
如果選擇直接上報(bào),請(qǐng)將Endpoint和URLPath替換為前提條件獲取的接入點(diǎn)信息。
如果選擇使用OpenTelemetry Collector轉(zhuǎn)發(fā),請(qǐng)將Endpoint替換為您本地部署的服務(wù)地址,并刪除Header信息。
func initProvider() func() { ctx := context.Background() traceClientHttp := otlptracehttp.NewClient( otlptracehttp.WithEndpoint("127.0.XX.XX:8080"), //Endpoint需替換為前提條件中獲取的接入點(diǎn)信息。 otlptracehttp.WithURLPath("/adapt_xxxxx/api/otlp/traces"), //URLPath需替換為前提條件中獲取的接入點(diǎn)信息。 otlptracehttp.WithInsecure()) otlptracehttp.WithCompression(1) traceExp, err := otlptrace.New(ctx, traceClientHttp) handleErr(err, "Failed to create the collector trace exporter") res, err := resource.New(ctx, resource.WithFromEnv(), resource.WithProcess(), resource.WithTelemetrySDK(), resource.WithHost(), resource.WithAttributes( // 在可觀測(cè)鏈路 OpenTelemetry 版后端顯示的服務(wù)名稱(chēng)。 semconv.ServiceNameKey.String(common.ClientServiceName), semconv.HostNameKey.String(common.ClientServiceHostName), ), ) handleErr(err, "failed to create resource") bsp := sdktrace.NewBatchSpanProcessor(traceExp) tracerProvider := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithResource(res), sdktrace.WithSpanProcessor(bsp), ) // 設(shè)置全局propagator為tracecontext(默認(rèn)不設(shè)置)。 otel.SetTextMapPropagator(propagation.TraceContext{}) otel.SetTracerProvider(tracerProvider) log.Println("OTEL init success") return func() { cxt, cancel := context.WithTimeout(ctx, time.Second) defer cancel() if err := traceExp.Shutdown(cxt); err != nil { otel.Handle(err) } } }
添加埋點(diǎn)。
tracer := otel.Tracer(common.TraceInstrumentationName) method, _ := baggage.NewMember("method", "repl") client, _ := baggage.NewMember("client", "cli") bag, _ := baggage.New(method, client) defaultCtx := baggage.ContextWithBaggage(context.Background(), bag) for { ctx, span := tracer.Start(defaultCtx, "ExecuteRequest") makeRequest(ctx) span.End() time.Sleep(time.Duration(1) * time.Second) }
啟動(dòng)應(yīng)用程序。
go run main.go
登錄ARMS控制臺(tái)后,在 頁(yè)面選擇目標(biāo)應(yīng)用,查看鏈路數(shù)據(jù)。
說(shuō)明語(yǔ)言列顯示圖標(biāo)的應(yīng)用為接入應(yīng)用監(jiān)控的應(yīng)用,顯示-圖標(biāo)的應(yīng)用為接入可觀測(cè)鏈路 OpenTelemetry 版的應(yīng)用。