【GO】LGTM_Grafana_gozero_配置trace(4)_代码实操及追踪

news2024/11/24 2:21:57

最近在尝试用 LGTM 来实现 Go 微服务的可观测性,就顺便整理一下文档。

Tempo 会分为 4 篇文章:

  1. Tempo 的架构
  2. 官网测试实操跑通
  3. gin 框架发送 trace 数据到 tempo
  4. go-zero 微服务框架发送数据到 tempo

本文就是写一下如何在 go-zero 微服务框架里面配置 trace 及 trace 的 handler 在哪里

代码地址:lgtm/example/go-zero-lgtm at main · zxmfke/lgtm (github.com)

这个代码里面包含一个 order 的 api 服务和一个 user 的 rpc 服务


go-zero 的服务接入 trace,是比较简单的,只需要在配置项中,配置 Telemetry 里面的参数就可以了。

Telemetry 配置

在 /etc 下有配置文件,其中配置:

...

Telemetry:
  Name: "order"
  Endpoint: "127.0.0.1:4318"
  Batcher: "otlphttp"

...

源码(core/trace/config.go)中可以配置的参数:

type Config struct {
	Name     string  `json:",optional"`
	Endpoint string  `json:",optional"`
	Sampler  float64 `json:",default=1.0"`
	Batcher  string  `json:",default=jaeger,options=jaeger|zipkin|otlpgrpc|otlphttp|file"`
	// OtlpHeaders represents the headers for OTLP gRPC or HTTP transport.
	// For example:
	//  uptrace-dsn: 'http://project2_secret_token@localhost:14317/2'
	OtlpHeaders map[string]string `json:",optional"`
	// OtlpHttpPath represents the path for OTLP HTTP transport.
	// For example
	// /v1/traces
	OtlpHttpPath string `json:",optional"`
	// Disabled indicates whether StartAgent starts the agent.
	Disabled bool `json:",optional"`
}

主要就是配置:

  • Name:服务名称
  • Endpoint:Trace provider 的 IP 地址
  • Batcher:用哪一种 provider 类型

注意,Disabled 如果没有设置为 true,就默认表示发送 trace 数据

Grafana Tempo Trace Data

请求接口后,trace 数据会发送到 Grafana 的 Tempo 里面,如下图:

在这里插入图片描述

可以看到分为三段:

  • order-api 收到请求的时候
  • order-api 请求 user-rpc 的时候
  • user-rpc 收到请求的时候

接下来我们可以追踪一下源码看看是在哪里发送的 trace 数据

追踪代码
初始化

order

order 是 api 服务,Telemetry 初始化的逻辑:

  • order.go

    // L24
    server := rest.MustNewServer(c.RestConf)
    
  • go-zero/rest/server.go

    // L35
    func MustNewServer(c RestConf, opts ...RunOption) *Server {
    	server, err := NewServer(c, opts...)
    	...
    }
    
    // L46
    func NewServer(c RestConf, opts ...RunOption) (*Server, error) {
    	if err := c.SetUp(); err != nil {
    		return nil, err
    	}
    	...
    
    	return server, nil
    }
    
  • go-zero/core/sevice/serviceconf.go

    // L44
    func (sc ServiceConf) SetUp() error {
    	...
    	trace.StartAgent(sc.Telemetry)
    	...
    	return nil
    }
    
  • go-zero/core/trace/agent.go

    // L39
    func StartAgent(c Config) {
    	...
    
    	// if error happens, let later calls run.
    	if err := startAgent(c); err != nil {
    		return
    	}
    
    	...
    }
    

user

  • user.go

    // L29
    s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
    	userclient.RegisterUserServer(grpcServer, srv)
    
        if c.Mode == service.DevMode || c.Mode == service.TestMode {
    		reflection.Register(grpcServer)
    	}
    })
    defer s.Stop()
    
  • go-zero/zrpc/server.go

    // L23 
    func MustNewServer(c RpcServerConf, register internal.RegisterFn) *RpcServer {
    	server, err := NewServer(c, register)
    	logx.Must(err)
    	return server
    }
    
    // L30
    func NewServer(c RpcServerConf, register internal.RegisterFn) (*RpcServer, error) {
    	...
        
    	if err = c.SetUp(); err != nil {
    		return nil, err
    	}
    
    	return rpcServer, nil
    }
    
  • Setup() 跟 order 的一样了

Order api 的 trace handler

之前看过源码,go-zero 的 api 和 rpc 是分开两个目录,所以 api 的代码一定在 go-zero/rest 下面。 要在请求的收到的时候发送一个 trace 数据,只有可能以中间件的形式加入,因此可以找到 rest 下的 handler 文件夹,里面就有一个 tracinghandler.go。

源码位置:go-zero/rest/handler/tracinghandler.go

这个就类似上一篇的 gin server 加 trace middleware 一样。

func TracingHandler(serviceName, path string) func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		propagator := otel.GetTextMapPropagator()
		tracer := otel.GetTracerProvider().Tracer(trace.TraceName)

		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			ctx := propagator.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
			spanName := path
			if len(spanName) == 0 {
				spanName = r.URL.Path
			}
			spanCtx, span := tracer.Start(
				ctx,
				spanName,
				oteltrace.WithSpanKind(oteltrace.SpanKindServer),
				oteltrace.WithAttributes(semconv.HTTPServerAttributesFromHTTPRequest(
					serviceName, spanName, r)...),
			)
			defer span.End()

			// convenient for tracking error messages
			propagator.Inject(spanCtx, propagation.HeaderCarrier(w.Header()))
			next.ServeHTTP(w, r.WithContext(spanCtx))
		})
	}
}
User rpc 的 trace handler

同理,user 是 rpc 服务,所以就到 zrpc 下面找,按照惯性,找到 go-zero/zrpc/internal/serverinterceptors ,这个时候就可以看到 tracinginterceptor.go

源码位置:go-zero/zrpc/internal/serverinterceptors/tracinginterceptor.go

func UnaryTracingInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler) (interface{}, error) {
    ctx, span := startSpan(ctx, info.FullMethod)
    defer span.End()

    ztrace.MessageReceived.Event(ctx, 1, req)
    resp, err := handler(ctx, req)
    if err != nil {
       s, ok := status.FromError(err)
       if ok {
          span.SetStatus(codes.Error, s.Message())
          span.SetAttributes(ztrace.StatusCodeAttr(s.Code()))
          ztrace.MessageSent.Event(ctx, 1, s.Proto())
       } else {
          span.SetStatus(codes.Error, err.Error())
       }
       return nil, err
    }

    span.SetAttributes(ztrace.StatusCodeAttr(gcodes.OK))
    ztrace.MessageSent.Event(ctx, 1, resp)

    return resp, nil
}

找到这个,但是没有发现 order-api 调用 user 的 handler。就很奇怪,又返回 rest 里面找,不过还是没找到,后面才发现 zrpc/internal 下面有一个 clientinterceptors ,原来在这边。

func UnaryTracingInterceptor(ctx context.Context, method string, req, reply interface{},
	cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
	ctx, span := startSpan(ctx, method, cc.Target())
	defer span.End()

	ztrace.MessageSent.Event(ctx, 1, req)
	ztrace.MessageReceived.Event(ctx, 1, reply)

	if err := invoker(ctx, method, req, reply, cc, opts...); err != nil {
		s, ok := status.FromError(err)
		if ok {
			span.SetStatus(codes.Error, s.Message())
			span.SetAttributes(ztrace.StatusCodeAttr(s.Code()))
		} else {
			span.SetStatus(codes.Error, err.Error())
		}
		return err
	}

	span.SetAttributes(ztrace.StatusCodeAttr(gcodes.OK))
	return nil
}

ror(err)
if ok {
span.SetStatus(codes.Error, s.Message())
span.SetAttributes(ztrace.StatusCodeAttr(s.Code()))
} else {
span.SetStatus(codes.Error, err.Error())
}
return err
}

span.SetAttributes(ztrace.StatusCodeAttr(gcodes.OK))
return nil

}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1038177.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

套接字socket编程的基础知识点

目录 前言(必读) 网络字节序 网络中的大小端问题 为什么网络字节序采用的是大端而不是小端? 网络字节序与主机字节序之间的转换 字符串IP和整数IP 整数IP存在的意义 字符串IP和整数IP相互转换的方式 inet_addr函数(会自…

83、SpringBoot --- 下载和安装 MSYS2、 Redis

★ 下载和安装MSYS2(作用:可在Windows模拟一个Linux的编译环境) 得到Redis的编译环境——在Linux平台上,这一步可以省略。(1)登录MSYS2官网(http://repo.msys2.org/distrib/ )下载M…

前端新轮子Nue,号称替代Vue、React和Svelte

新的简约前端开发工具集Nue.js 于周三发布。在 Hacker News 上介绍它时,前端开发者和Nue.js 的创作者Tero Piirainen表示,它是 React、Vue、Next.js、Vite、Svelte 和 Astro 的替代品。他在 Nue.js的 FAQ 中进一步解释说,它是为网站和响应式用…

【Vue.js】使用Element搭建登入注册界面axios中GET请求与POST请求跨域问题

一,ElementUI是什么? Element UI 是一个基于 Vue.js 的桌面端组件库,它提供了一套丰富的 UI 组件,用于构建用户界面。Element UI 的目标是提供简洁、易用、美观的组件,同时保持灵活性和可定制性 二,Element…

Spring学习笔记6 Bean的实例化方式

Spring学习笔记5 GoF之工厂模式_biubiubiu0706的博客-CSDN博客 Spring为Bean提供了多种实例化方式,通常包括4中(目的:更加灵活) 1.通过构造方法实例化 2.通过简单工厂模式实例化 3.通过factory-bean实例化 4.通过FactoryBean接口实例化 新建模块 spring-005 依赖 <!--S…

自动化测试、压力测试、持续集成

因为项目的原因&#xff0c;前段时间研究并使用了 SoapUI 测试工具进行自测开发的 api。下面将研究的成果展示给大家&#xff0c;希望对需要的人有所帮助。 SoapUI 是什么&#xff1f; SoapUI 是一个开源测试工具&#xff0c;通过 soap/http 来检查、调用、实现 Web Service 的…

github想传至远程仓库显示fatal: remote origin already exists. (远程来源已经存在 解决办法)

参考:https://blog.csdn.net/qq_40428678/article/details/84074207 在当我们输入git remote add origin https://gitee.com/(github/码云账号)/(github/码云项目名).git 就会报如下的错 fatal: remote origin already exists. 翻译过来就是&#xff1a;致命&#xff1a;远程…

zabbix自定义监控、钉钉、邮箱报警 (五十六)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 一、实验准备 二、安装 三、添加监控对象 四、添加自定义监控项 五、监控mariadb 1、添加模版查看要求 2、安装mariadb、创建用户 3、创建用户文件 4、修改监控模版 5、…

新版Chromedriver在哪下载(Chromedriver 116.0.5845.188的寻找之旅)

不知道什么时候Chrome自动升级到116.0.5845.188了&#xff0c;害得我原来的Chromedriver 114无法使用了&#xff0c;无奈之下只好重新去下载。 可寻遍网络&#xff0c;都没找到Chromedriver116的版本。网上大多网友给的下载网址是chromedriver.storage.googleapis.com/index.ht…

数据结构与算法之时间复杂度和空间复杂度(C语言版)

1. 时间复杂度 1.1 概念 简而言之&#xff0c;算法中的基本操作的执行次数&#xff0c;叫做算法的时间复杂度。也就是说&#xff0c;我这个程序执行了多少次&#xff0c;时间复杂度就是多少。 比如下面这段代码的执行次数&#xff1a; void Func1(int N) {int count 0;for…

Ubuntu 20.04 安装MySQL 8.0.34

MySQL安装 sudo wget https://cdn.mysql.com/archives/mysql-8.0/mysql-server_8.0.31-1ubuntu20.04_amd64.deb-bundle.tar下载MySQL文件。 sudo mkdir /mysql8创建目录。 sudo tar -xf mysql-server_8.0.31-1ubuntu20.04_amd64.deb-bundle.tar -C /mysql8进行解压。 需…

结构体基础知识——(OneNote笔记本)

结构体基础知识——&#xff08;OneNote笔记本&#xff09; 代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h>//struct Stu //{ // //学生的相关属性 // char name[20]; // int age; // char sex[5]; // char tele[12]; //} s3, s4; //s3&#x…

RISC-V 基础指令汇总

加载指令 存储指令 PC寻址指令 auipc rd, imm这条指令把 imm &#xff08;立即数&#xff09;左移12位并带符号扩展到64位后&#xff0c;得到一个新的立即数&#xff0c;这个新的立即数是一个有符号的立即数&#xff0c;再加上当前 PC 值&#xff0c;然后存储到 rd 寄存器中。…

【面试经典150 | 滑动窗口】无重复字符的最长子串

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;滑动窗口 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等…

用git给github私有仓库上传文件

创建私有仓库可以参考这篇文章的前面7步&#xff1a; 关于Github私有仓库的创建 然后我想在私有仓库上传文件该怎么办呢&#xff1f; 在你的文件夹右键git bash 初始化git git init添加本地文件 git add .上传本地 git commit -m "first commit"设置branch&am…

NetSuite BOM成本查询

这是个23.2的新功能&#xff0c;如题所示是对BOM成本的一个查询工具&#xff0c;是对之前版本那个无用的“Costed Bill of Materials Inquiry”的一次救赎。 其重要的功能是&#xff1a; •基于BOM所使用的版本、工艺路线和成本模板&#xff0c;通过Break Down的方式计算一个装…

Spring学习笔记5 GoF之工厂模式

Spring学习笔记4 Bean的作用域_biubiubiu0706的博客-CSDN博客 出了GoF23种设计模式.还有javaee的设计模式(DAO模式,MVC模式) 设计模式:是一种可以被重复利用的解决方案 GoF23种设计模式可分为三大类: 创建型(5个):解决对象创建问题. 单例模式&#xff0c;工厂方法模式&#x…

18795-2012 茶叶标准样品制备技术条件

声明 本文是学习GB-T 18795-2012 茶叶标准样品制备技术条件. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了各类茶叶(除再加工茶)标准样品的制备、包装、标签、标识、证书和有效期。 本标准适用于各类茶叶(除再加工茶)感官品质…

2023 “华为杯” 中国研究生数学建模竞赛(E题)深度剖析|数学建模完整代码+建模过程全解全析

​ 问题一 血肿扩张风险相关因素探索建模 思路&#xff1a; 根据题目要求,首先需要判断每个患者是否发生了血肿扩张事件。根据定义,如果后续检查的血肿体积比首次检查增加≥6 mL或≥33%,则判断为发生了血肿扩张。 具体判断步骤: (1) 从表1中提取每个患者的入院首次影像检查…

机器学习之监督学习,无监督学习,强化学习相关概念

文章目录 1. 监督学习&#xff08;Supervised Learning&#xff09;2. 无监督学习&#xff08;Unsupervised Learning&#xff09;3. 强化学习&#xff08;Reinforcement Learning&#xff09;总结 机器学习可以按照模型使用情况分为三大类&#xff1a;监督学习、无监督学习和强…