[系列] go-gin-api 路由中间件 - Jaeger 链路追踪(六)
概述
首先同步下项目概况:

上篇文章分享了,路由中间件 - Jaeger 链路追踪(理论篇),这篇文章咱们接着分享:路由中间件 - Jaeger 链路追踪(实战篇)。
这篇文章,确实让大家久等了,主要是里面有一些技术点都是刚刚研究的,没有存货。

先看下咱们要实现的东西:

API 调用了 5 个服务,其中 4 个 gRPC 服务,1 个 HTTP 服务,服务与服务之间又相互调用:
- Speak 服务,又调用了 Listen 服务 和 Sing 服务。
- Read 服务,又调用了 Listen 服务 和 Sing 服务。
- Write 服务,又调用了 Listen 服务 和 Sing 服务。
咱们要实现的就是查看 API 调用的链路。
关于一些理论的东西,大家可以去看看上篇文章或查阅一些资料,这篇文章就是实现怎么用。
OK,开整。
Jaeger 部署
咱们使用 All in one 的方式,进行本地部署。
下载地址:https://www.jaegertracing.io/download/
我的电脑是 macOS 选择 -> Binaries -> macOS
下载后并解压,会发现以下文件:
- example-hotrod
- jaeger-agent
- jaeger-all-in-one
- jaeger-collector
- jaeger-ingester
- jaeger-query
进入到解压后的目录执行:
./jaeger-all-in-one
目测启动后,访问地址:

到这,Jaeger 已经部署成功了。
准备测试服务
准备的五个测试服务如下:
听(listen)
- 端口:9901
- 通讯:gRPC
说(speak)
- 端口:9902
- 通讯:gRPC
读(read)
- 端口:9903
- 通讯:gRPC
写(write)
- 端口:9904
- 通讯:gRPC
唱(sing)
- 端口:9905
- 通讯:HTTP
听、说、读、写、唱,想这几个服务的名称就花了好久 ~
我默认大家都会写 grpc 服务,如果不会写的,可以查看下我原来的文章《Go gRPC Hello World》。
应用示例
实例化 Tracer
func NewJaegerTracer(serviceName string, jaegerHostPort string) (opentracing.Tracer, io.Closer, error) {
cfg := &jaegerConfig.Configuration {
Sampler: &jaegerConfig.SamplerConfig{
Type : "const", //固定采样
Param : 1, //1=全采样、0=不采样
},
Reporter: &jaegerConfig.ReporterConfig{
LogSpans : true,
LocalAgentHostPort : jaegerHostPort,
},
ServiceName: serviceName,
}
tracer, closer, err := cfg.NewTracer(jaegerConfig.Logger(jaeger.StdLogger))
if err != nil {
panic(fmt.Sprintf("ERROR: cannot init Jaeger: %v\n", err))
}
opentracing.SetGlobalTracer(tracer)
return tracer, closer, err
}
HTTP 注入
injectErr := jaeger.Tracer.Inject(span.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))
if injectErr != nil {
log.Fatalf("%s: Couldn't inject headers", err)
}
HTTP 拦截
spCtx, err := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(c.Request.Header))
if err != nil {
ParentSpan = Tracer.StartSpan(c.Request.URL.Path)
defer ParentSpan.Finish()
} else {
ParentSpan = opentracing.StartSpan(
c.Request.URL.Path,
opentracing.ChildOf(spCtx),
opentracing.Tag{Key: string(ext.Component), Value: "HTTP"},
ext.SpanKindRPCServer,
)
defer ParentSpan.Finish()
}
gRPC 注入
func ClientInterceptor(tracer opentracing.Tracer, spanContext opentracing.SpanContext) grpc.UnaryClientInterceptor {
return func(ctx context.Context, method string,
req, reply interface{}, cc *grpc.ClientConn,
invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
span := opentracing.StartSpan(
"call gRPC",
opentracing.ChildOf(spanContext),
opentracing.Tag{Key: string(ext.Component), Value: "gRPC"},
ext.SpanKindRPCClient,
)
defer span.Finish()
md, ok := metadata.FromOutgoingContext(ctx)
if !ok {
md = metadata.New(nil)
} else {
md = md.Copy()
}
err := tracer.Inject(span.Context(), opentracing.TextMap, MDReaderWriter{md})
if err != nil {
span.LogFields(log.String("inject-error", err.Error()))
}
newCtx := metadata.NewOutgoingContext(ctx, md)
err = invoker(newCtx, method, req, reply, cc, opts...)
if err != nil {
span.LogFields(log.String("call-error", err.Error()))
}
return err
}
}
gRPC 拦截
func serverInterceptor(tracer opentracing.Tracer) grpc.UnaryServerInterceptor {
return func(ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler) (resp interface{}, err error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.New(nil)
}
spanContext, err := tracer.Extract(opentracing.TextMap, MDReaderWriter{md})
if err != nil && err != opentracing.ErrSpanContextNotFound {
grpclog.Errorf("extract from metadata err: %v", err)
} else {
span := tracer.StartSpan(
info.FullMethod,
ext.RPCServerOption(spanContext),
opentracing.Tag{Key: string(ext.Component), Value: "gRPC"},
ext.SpanKindRPCServer,
)
defer span.Finish()
ParentContext = opentracing.ContextWithSpan(ctx, span)
}
return handler(ParentContext, req)
}
}
上面是一些核心的代码,涉及到的全部代码我都会上传到 github,供下载。
运行
启动服务
// 启动 Listen 服务
cd listen && go run main.go
// 启动 Speak 服务
cd speak && go run main.go
// 启动 Read 服务
cd read && go run main.go
// 启动 Write 服务
cd write && go run main.go
// 启动 Sing 服务
cd sing && go run main.go
// 启动 go-gin-api 服务
cd go-gin-api && go run main.go
访问路由
http://127.0.0.1:9999/jaeger_test
效果


就到这吧。
API 源码地址
https://github.com/xinliangnote/go-gin-api
Service 源码地址
https://github.com/xinliangnote/go-jaeger-demo
go-gin-api 系列文章
[系列] go-gin-api 路由中间件 - Jaeger 链路追踪(六)的更多相关文章
- [系列] go-gin-api 路由中间件 - Jaeger 链路追踪(五)
概述 首先同步下项目概况: 上篇文章分享了,路由中间件 - 捕获异常,这篇文章咱们分享:路由中间件 - Jaeger 链路追踪. 啥是链路追踪? 我理解链路追踪其实是为微服务架构提供服务的,当一个请求 ...
- go-gin-api 路由中间件 - Jaeger 链路追踪
概述 首先同步下项目概况: 上篇文章分享了,路由中间件 - Jaeger 链路追踪(理论篇). 这篇文章咱们分享:路由中间件 - Jaeger 链路追踪(实战篇). 说实话,这篇文章确实让大家久等了, ...
- go-zero docker-compose 搭建课件服务(八):集成jaeger链路追踪
0.转载 go-zero docker-compose 搭建课件服务(八):集成jaeger链路追踪 0.1源码地址 https://github.com/liuyuede123/go-zero-co ...
- spring cloud 系列第7篇 —— sleuth+zipkin 服务链路追踪 (F版本)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.简介 在微服务架构中,几乎每一个前端的请求都会经过多个服务单元协调来提 ...
- [系列] go-gin-api 路由中间件 - 签名验证(七)
目录 概览 MD5 组合 AES 对称加密 RSA 非对称加密 如何调用? 性能测试 PHP 与 Go 加密方法如何互通? 源码地址 go-gin-api 系列文章 概览 首先同步下项目概况: 上篇文 ...
- go-gin-api 路由中间件 - 签名验证(七)
概览 首先同步下项目概况: 上篇文章分享了,路由中间件 - Jaeger 链路追踪(实战篇),文章反响真是出乎意料, 「Go中国」 公众号也转发了,有很多朋友加我好友交流,直呼我大神,其实我哪是什么大 ...
- 微服务从代码到k8s部署应有尽有系列(十二、链路追踪)
我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...
- 带你十天轻松搞定 Go 微服务系列(九、链路追踪)
序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Auth 验证 ...
- .NET Core 中的日志与分布式链路追踪
目录 .NET Core 中的日志与分布式链路追踪 .NET Core 中的日志 控制台输出 非侵入式日志 Microsoft.Extensions.Logging ILoggerFactory IL ...
随机推荐
- 随笔编号-07 JS针对时间操作
//获取完整的当前日期 var date=new Date; var year=date.getFullYear(); var month=date.getMonth()+1; month =(mon ...
- PHP 递归读取无限级分类
/** * [获取第一级分类] * 20170829 * * @return array */ public function getCateList(){ $this->catelog = [ ...
- 使用Springboot Cache做简单缓存
使用Springboot Cache做简单缓存 1.简单介绍 当我们需要展示数据的时候,后台会根据需要从服务器中获取数据,但是频繁的请求数据库会对服务造成压力,于是我们引入了缓存这个概念. 当 ...
- 设置VS2015背景图片(转载)
设置方法很简单:安装扩展ClaudiaIDE 1.在这里下载扩展,https://visualstudiogallery.msdn.microsoft.com/9ba50f8d-f30c-4e33-a ...
- javaScript 基础知识汇总(五)
1.垃圾回收 JavaScript 的内存管理是自动的,不能强制执行或者阻止执行 可达性 JavaScript中主要的内存管理概念是可达性. 什么是可达性? 定义一个对象 let user = { n ...
- 【selenium】- selenium简介
本文由小编根据慕课网视频亲自整理,转载请注明出处和作者. 1. Selenium的来历 2. Selenium家庭成员 Selenium RC: Selenium 1 Selenium Webdriv ...
- POJ-3169 Layout (差分约束+SPFA)
POJ-3169 Layout:http://poj.org/problem?id=3169 参考:https://blog.csdn.net/islittlehappy/article/detail ...
- POJ-3662 Telephone Lines 二分+双端队列
题目传送门 题意:有n个点, p条路,每条道路有个花费Li, 然后现在要建一条1-n的路线,然后可以选k条道路免费, 然后可以在剩下的道路中选择价格最高的边支付费用, 求这个答案最小. 题解: 二分答 ...
- 图论之拓扑排序 poj 2367 Genealogical tree
题目链接 http://poj.org/problem?id=2367 题意就是给定一系列关系,按这些关系拓扑排序. #include<cstdio> #include<cstrin ...
- PAT 天梯杯 L2-014 列车调度
火车站的列车调度铁轨的结构如下图所示. Figure 两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道.每趟列车从入口可以选择任意一条轨道进入,最后从出口 ...