本文将为您介绍如何使用 gin Jaeger 中间件上报 Go 应用数据。
操作步骤
步骤1:获取接入点和 Token
1. 登录 腾讯云可观测平台 控制台。
2. 在左侧菜单栏中选择应用性能监控 > 应用监控,单击应用列表 > 接入应用。
3. 在右侧弹出的数据接入抽屉框中,单击 Go 语言。
4. 在接入 Go 应用页面,选择您所要接入的地域以及业务系统。
5. 选择接入协议类型为 Jaeger。
6. 上报方式选择您所想要的上报方式,获取您的接入点和 Token。
说明:
内网上报:使用此上报方式,您的服务需运行在腾讯云 VPC。通过 VPC 直接联通,在避免外网通信的安全风险同时,可以节省上报流量开销。
外网上报:当您的服务部署在本地或非腾讯云 VPC 内,可以通过此方式上报数据。请注意外网通信存在安全风险,同时也会造成一定上报流量费用。
步骤2:安装 Jaeger Agent
1. 下载 Jaeger Agent。
2. 在控制台执行以下命令启动 Agent。
nohup ./jaeger-agent --reporter.grpc.host-port={{collectorRPCHostPort}} --agent.tags=token={{token}}
步骤3:选择上报端类型上报应用数据
选择上报端类型,通过 gin Jaeger 中间件上报 Go 应用数据:
服务端
1. 在服务端侧引入
opentracing-contrib/go-gin
依赖依赖路径:
github.com/opentracing-contrib/go-gin
版本要求: ≥
v0.0.0-20201220185307-1dd2273433a4
2. 配置 Jaeger ,创建 Trace 对象。示例如下:
cfg := &jaegerConfig.Configuration{ServiceName: ginServerName, //对服务发起请求的调用链,填写服务名称Sampler: &jaegerConfig.SamplerConfig{ //采样策略的配置Type: "const",Param: 1,},Reporter: &jaegerConfig.ReporterConfig{ //配置客户端如何上报trace信息,所有字段都是可选的LogSpans: true,LocalAgentHostPort: endPoint,},//Token配置Tags: []opentracing.Tag{ //设置tag,token等信息可存于此opentracing.Tag{Key: "token", Value: token}, //设置token},}tracer, closer, err := cfg.NewTracer(jaegerConfig.Logger(jaeger.StdLogger)) //根据配置得到tracer
3. 配置中间件
r := gin.Default()//传入tracerr.Use(ginhttp.Middleware(tracer))
说明
官方默认 OperationName 是 HTTP + HttpMethod,建议使用
HTTP + HttpMethod + URL
可以分析到具体接口,接口主要 URL 应是参数名,不是具体参数值。 具体用法如下:
正确:/user/{id}
错误:
/user/1
r.Use(ginhttp.Middleware(tracer, ginhttp.OperationNameFunc(func(r *http.Request) string {return fmt.Sprintf("testtestheling HTTP %s %s", r.Method, r.URL.String())})))
完整代码如下:
// Copyright © 2019-2020 Tencent Co., Ltd.// This file is part of tencent project.// Do not copy, cite, or distribute without the express// permission from Cloud Monitor group.package gindemoimport ("fmt""github.com/gin-gonic/gin""github.com/opentracing-contrib/go-gin/ginhttp""github.com/opentracing/opentracing-go""github.com/uber/jaeger-client-go"jaegerConfig "github.com/uber/jaeger-client-go/config""net/http")// 服务名 服务唯一标示,服务指标聚合过滤依据。const ginServerName = "demo-gin-server"// StartServerfunc StartServer() {//初始化jaeger,得到tracercfg := &jaegerConfig.Configuration{ServiceName: ginServerName, //对服务发起请求的调用链,填写服务名称Sampler: &jaegerConfig.SamplerConfig{ //采样策略的配置Type: "const",Param: 1,},Reporter: &jaegerConfig.ReporterConfig{ //配置客户端如何上报trace信息,所有字段都是可选的LogSpans: true,LocalAgentHostPort: endPoint,},//Token配置Tags: []opentracing.Tag{ //设置tag,token等信息可存于此opentracing.Tag{Key: "token", Value: token}, //设置token},}tracer, closer, err := cfg.NewTracer(jaegerConfig.Logger(jaeger.StdLogger)) //根据配置得到tracerif err != nil {panic(fmt.Sprintf("ERROR: fail init Jaeger: %v\\n", err))}defer closer.Close()r := gin.Default()//这里说明一下,官方默认 OperationName 是 HTTP + HttpMethod,//建议使用 HTTP + HttpMethod + URL 可以分析到具体接口,具体用法如下//PS:Restful 接口主要URL应该是参数名,不是具体参数值。 如: 正确:/user/{id}, 错误:/user/1r.Use(ginhttp.Middleware(tracer, ginhttp.OperationNameFunc(func(r *http.Request) string {return fmt.Sprintf("HTTP %s %s", r.Method, r.URL.String())})))r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"message": "pong",})})r.Run() // 监听 0.0.0.0:8080}
客户端
1. 客户端侧由于需要模拟 HTTP 请求,引入
opentracing-contrib/go-stdlib/nethttp
依赖。依赖路径:
github.com/opentracing-contrib/go-stdlib/nethttp
版本要求: ≥
v1.0.0
2. 配置 Jaeger,创建 Trace 对象。示例如下:
cfg := &jaegerConfig.Configuration{ServiceName: ginClientName, //对服务发起请求的的调用链,填写服务名称Sampler: &jaegerConfig.SamplerConfig{ //采样策略的配置Type: "const",Param: 1,},Reporter: &jaegerConfig.ReporterConfig{ //配置客户端如何上报trace信息,所有字段都是可选的LogSpans: true,LocalAgentHostPort: endPoint,},//Token配置Tags: []opentracing.Tag{ //设置tag,token等信息可存于此opentracing.Tag{Key: "token", Value: token}, //设置token},}tracer, closer, err := cfg.NewTracer(jaegerConfig.Logger(jaeger.StdLogger)) //根据配置得到tracer
3. 构建 span 并把 span 放入 conext 中,示例如下:
span := tracer.StartSpan("CallDemoServer") //构建spanctx := opentracing.ContextWithSpan(context.Background(), span) //将span的引用放入conext中
4. 构建带 tracer 的 Request 请求,示例如下:
//构建http的请求req, err := http.NewRequest(http.MethodGet,fmt.Sprintf("http://localhost%s/ping", ginPort),nil,)req = req.WithContext(ctx)//构建带tracer的请求req, ht := nethttp.TraceRequest(tracer, req)
5. 发起 HTTP 请求,并获得返回结果。
httpClient := &http.Client{Transport: &nethttp.Transport{}} //初始化http客户端res, err := httpClient.Do(req)//..省略err判断body, err := ioutil.ReadAll(res.Body)//..省略err判断log.Printf(" %s recevice: %s\\n", clientServerName, string(body))
完整代码如下:
// Copyright © 2019-2020 Tencent Co., Ltd.// This file is part of tencent project.// Do not copy, cite, or distribute without the express// permission from Cloud Monitor group.package gindemoimport ("context""fmt""github.com/opentracing-contrib/go-stdlib/nethttp""github.com/opentracing/opentracing-go""github.com/opentracing/opentracing-go/ext"opentracingLog "github.com/opentracing/opentracing-go/log""github.com/uber/jaeger-client-go"jaegerConfig "github.com/uber/jaeger-client-go/config""io/ioutil""log""net/http")const (// 服务名 服务唯一标示,服务指标聚合过滤依据。ginClientName = "demo-gin-client"ginPort = ":8080"endPoint = "xxxxx:6831" // 本地agent地址token = "abc")// StartClient 下的 gin client 也是标准的 http client.func StartClient() {cfg := &jaegerConfig.Configuration{ServiceName: ginClientName, //对服务发起请求的调用链,填写服务名称Sampler: &jaegerConfig.SamplerConfig{ //采样策略的配置Type: "const",Param: 1,},Reporter: &jaegerConfig.ReporterConfig{ //配置客户端如何上报trace信息,所有字段都是可选的LogSpans: true,LocalAgentHostPort: endPoint,},//Token配置Tags: []opentracing.Tag{ //设置tag,token等信息可存于此opentracing.Tag{Key: "token", Value: token}, //设置token},}tracer, closer, err := cfg.NewTracer(jaegerConfig.Logger(jaeger.StdLogger)) //根据配置得到tracerdefer closer.Close()if err != nil {panic(fmt.Sprintf("ERROR: fail init Jaeger: %v\\n", err))}//构建span,并将span放入context中span := tracer.StartSpan("CallDemoServer")ctx := opentracing.ContextWithSpan(context.Background(), span)defer span.Finish()// 构建http请求req, err := http.NewRequest(http.MethodGet,fmt.Sprintf("http://localhost%s/ping", ginPort),nil,)if err != nil {HandlerError(span, err)return}// 构建带tracer的请求req = req.WithContext(ctx)req, ht := nethttp.TraceRequest(tracer, req)defer ht.Finish()// 初始化http客户端httpClient := &http.Client{Transport: &nethttp.Transport{}}// 发起请求res, err := httpClient.Do(req)if err != nil {HandlerError(span, err)return}defer res.Body.Close()body, err := ioutil.ReadAll(res.Body)if err != nil {HandlerError(span, err)return}log.Printf(" %s recevice: %s\\n", ginClientName, string(body))}// HandlerError handle error to span.func HandlerError(span opentracing.Span, err error) {span.SetTag(string(ext.Error), true)span.LogKV(opentracingLog.Error(err))}