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

最近在尝试用 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: 1.5.5
go: 1.20.3


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/tracesOtlpHttpPath 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 := pathif 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 messagespropagator.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.mzph.cn/news/87177.shtml

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

相关文章

暗月中秋靶场活动writeup

前言 暗月在中秋节搞了个靶场活动,一共有4个flag,本着增长经验的想法参加了本次活动,最终在活动结束的时候拿到了3个flag,后面看了其他人的wp也复现拿到第四个flag。过程比较曲折,所以记录一下。 靶场地址 103.108.…

Chinese-LLaMA-AIpaca

文章目录 关于 Chinese-LLaMA-Alpaca一、LLaMA模型 --> HF格式二、合并LoRA权重,生成全量模型权重方式1:单LoRA权重合并方式2:多LoRA权重合并(适用于Chinese-Alpaca-Plus )三、使用 Transformers 进行推理四、使用 webui 搭建界面1、克隆text-generation-webui并安装必…

基础排序算法

插入排序(insertion sort) 插入排序每次循环将一个元素放置在适当的位置。像抓牌一样。手里的排是有序的,新拿一张牌,与手里的牌进行比较将其放在合适的位置。 插入排序要将待排序的数据分成两部分,一部分有序&#…

Leetcode 409. 最长回文串

文章目录 题目代码&#xff08;9.24 首刷自解&#xff09; 题目 Leetcode 409. 最长回文串 代码&#xff08;9.24 首刷自解&#xff09; class Solution { public:int longestPalindrome(string s) {unordered_map<char, int> mp;for(char c : s) mp[c];int res 0;int…

什么是Selenium?使用Selenium进行自动化测试!

你知道什么是 Selenium 吗&#xff1f;你知道为什么要使用它吗&#xff1f;答案就在本文中&#xff0c;很高兴能够与你共飧。 自动化测试正席卷全球&#xff0c;Selenium 认证是业界最抢手的技能之一。 什么是 Selenium&#xff1f; Selenium 是一种开源工具&#xff0c;用于…

2023蓝帽杯半决赛misc题目复现

后续会逐渐完善&#xff1a; misc--排排坐吃果果 我真是无大语了&#xff0c;对于我的死脑筋&#xff0c;文件一打开是一片白色&#xff0c;但是点开单元格会看到里面有数字&#xff0c;我想到了修改单元格的格式&#xff0c;就是没想到转换字体的颜色&#xff0c;对此我表示…

阿里云ESS弹性伸缩核心概念与基本使用

文章目录 1.ESS弹性伸缩基本概念1.1.弹性伸缩概念1.2.弹性伸缩应用场景1.3.弹性伸缩的应用模式 2.开通ESS弹性伸缩服务3.为KodCloud云盘集群创建弹性伸缩组3.1.创建伸缩组3.2.设置伸缩组的名称、类型、移除策略、健康检查3.3.设置组内实例数、冷却时间、网络类型、扩缩容策略、…

【数据结构与算法】不就是数据结构

前言 嗨喽小伙伴们你们好呀&#xff0c;好久不见了,我已经好久没更新博文了&#xff01;之前因为实习没有时间去写博文&#xff0c;现在已经回归校园了。我看了本学期的课程中有数据结构这门课程&#xff08;这么课程特别重要&#xff09;&#xff0c;因为之前学过一点&#xf…

华为数通方向HCIP-DataCom H12-831题库(单选题:41-60)

第41题 除了虚连接之外,OSPFV3的Hello报文源IPv6地址是哪种类型的IPv6地址? A、IPv6任播地址 B、唯一本地地址 C、全球单播地址 D、链路本地地址 答案: D 解析: 这里题目是源IPv6,不是目的IPv6,与另一题类似 第42题 下列描述中关于MPLS网络中配置静态LSP正确的是? A、…

简单线性回归(Simple Linear Regression)

简单线性回归(Simple Linear Regression) 简单线性回归(Simple Linear Regression)简介理解数据数据处理读取数据数据预览数据探索数据统计信息数据类型查看数据的直方图通过散点图查看数据的相关关系相关系数建立模型创建训练数据和测试数据建立简单线性回归模型查看回归方…

计算机等级考试—信息安全三级真题六

目录 一、单选题 二、填空题 三、综合题 一、单选题

工厂漏水怎么预防?教你一招,百试百灵

随着工业化的迅速发展&#xff0c;工厂和生产设施在现代社会中扮演着至关重要的角色。然而&#xff0c;这些设施在日常运营中也面临着各种各样的风险和挑战&#xff0c;其中之一是水浸事件。 水浸事件可能是由于天灾、设备故障、管道泄漏或人为失误等原因引发的&#xff0c;但无…

基于STM32和LORA组网的养老院智能控制系统设计(第十八届研电赛)

一、整体功能 数据采集从机1采集烟雾浓度&#xff0c;PM2.5浓度&#xff0c;甲醛浓度&#xff1b;从机2采集温湿度&#xff0c;光照强度&#xff0c;噪声强度&#xff0c;老人体感温度&#xff1b;从机3收集厨房饮用水的TDS值。3个数据采集从机将采集到的数据显示在本地OLED屏…

Sqilte3初步教程

文章目录 安装创建数据库创建和删除表插入行数据 安装 Windows下安装&#xff0c;首先到下载页面&#xff0c;下载Windows安装软件&#xff0c;一般是 sqlite-dll-win32-*.zip sqlite-tools-win32-*.zip下载之后将其内容解压到同一个文件夹下&#xff0c;我把它们都放在了D:\…

使用Python+Flask/Moco框架/Fiddler搭建简单的接口Mock服务

一、Mock测试 1、介绍 mock&#xff1a;就是对于一些难以构造的对象&#xff0c;使用虚拟的技术来实现测试的过程mock测试&#xff1a;在测试过程中&#xff0c;对于某些不容易构造或者不容易获取的对象&#xff0c;可以用一个虚拟的对象来代替的测试方法接口mock测试&#x…

查看吾托帮88.47的docker里的tomcat日志

步骤如下 &#xff08;1&#xff09;ssh &#xff08;2&#xff09;ssh root192.168.88.47 等待输入密码&#xff1a;fytest &#xff08;3&#xff09;pwd #注释&#xff1a;输出/root &#xff08;4&#xff09;docker exec -it wetoband_deploy /bin/bash #注释&#xff1…

基于springboot小区疫情防控系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

Python爬虫程序设置代理常见错误代码及解决方法

Python爬虫程序设置代理是爬虫程序中常用的技巧&#xff0c;可以有效地绕过IP限制&#xff0c;提高爬虫程序的稳定性和效率。然而&#xff0c;在设置代理时&#xff0c;常会出现各种错误代码&#xff0c;这些错误代码可能会影响程序的正常运行&#xff0c;甚至导致程序崩溃。本…

12款最火的AI画图软件,助你探索创新设计

ChatGPT火爆出圈&#xff0c;AI画图软件也如雨后春笋般流行起来。各类AI画图的软件工具横空出世&#xff0c;设计师与其焦虑工作会不会被人工智能取代&#xff0c;不如践行“工欲善其事必先利其器”&#xff0c;开拓思路&#xff0c;打开格局&#xff0c;好好地探索下如何利用好…

spring boot +vue 博客系统,开源的资源网站

spring boot vue 博客系统&#xff0c;开源的资源网站&#xff08;Aurora前后端分离博客) 体验地址&#xff1a;http://blog.tlzcf.vip/ 相关技术 前端&#xff1a; 样式来自于&#xff1a;hexo的aurora主题基础框架&#xff1a;vue3(前台) vue2(后台)状态管理&#xff1a;…