前提条件
完成vpce接入。
背景信息
OpenTelemetry Go SDK提供了Go语言的分布式链路追踪能力,您可以直接使用OTLP gRPC或者HTTP协议向APM服务端上报数据。
接入步骤
- 添加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"
)
- 查看接入点信息。
应用列表的接入指引会根据您所在资源池提供“通过 HTTP 上报数据”和“通过 gRPC 上报数据”的ENDPOINT(天翼云vpc网络接入点)、鉴权TOKEN信息。
- 初始化OpenTelemetry Go SDK。
(注意需将token和endpoint替换成相应地域的接入点信息。)
注意需将token和endpoint替换成相应地域的接入点信息。
方式1:使用HTTP协议上报数据。
func initProvider() func() {
ctx := context.Background()
auth := map[string]string{
"x-ctg-authorization": "<token>", // 替换成token信息
}
traceClient := otlptracehttp.NewClient(
otlptracehttp.WithInsecure(),
otlptracehttp.WithEndpoint("<endpoint>"), //替换成otel http的上报地址。
otlptracehttp.WithURLPath("/v1/traces"),
otlptracehttp.WithHeaders(auth),
otlptracehttp.WithDialOption(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("otel-go-client-demo"),
// 在APM控制台显示的主机名称。
semconv.HostNameKey.String("your-host-name"),
// 在APM控制台显示的服务端地址。
semconv.NetSockHostAddr("service_addr"),
// 在APM控制台显示的客户端地址。
semconv.NetSockPeerAddr("client_addr"),
),
)
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协议上报数据。
funcinitProviderGrpc()func(){
ctx := context.Background()
auth :=map[string]string{
"x-ctg-authorization":"<token>",//接入流程里面获取token信息
}
traceClient := otlptracegrpc.NewClient(
otlptracegrpc.WithInsecure(),
otlptracegrpc.WithEndpoint("<endpoint>"),//替换成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(
// 在可观测链路 OpenTelemetry 版后端显示的服务名称。
semconv.ServiceNameKey.String("otel-go-client-demo_provider"),
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)
returnfunc(){
cxt, cancel := context.WithTimeout(ctx, time.Second)
defercancel()
if err := traceExp.Shutdown(cxt); err !=nil{
otel.Handle(err)
}
}
}
- client端上报例子。
funcsendReq(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)
}
}
funcdoClient(url string, ctx context.Context){
// 不断请求数据
for{
sendReq(url, ctx)
time.Sleep(3* time.Second)
}
}
funcmain(){
shutdown :=initProvider()
defershutdown()
url := flag.String("server","http://localhost:8070/hello","server url")
flag.Parse()
bag,_:= baggage.Parse("username=xxx")
ctx := baggage.ContextWithBaggage(context.Background(), bag)
doClient(*url, ctx)
}
- 服务端上报例子。
funchandler(){
uk := attribute.Key("username")//加点属性
helloHandler :=func(w http.ResponseWriter, req *http.Request){
ctx := req.Context()
//继续调用下一个服务最终效果是client-》hello-》hello1
sendReq("http://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)
}
funcmain(){
flag.Parse()
shutdown :=initProvider()
defershutdown()
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)
}
}
- 通过以上步骤,最后就在APM控制台的应用列表页面选择目标应用,查看监控数据。