链路追踪之Jaeger
官方地址:https://www.jaegertracing.io/
[安装]
官方提供了两个安装方式,
1. 基于二进制(https://www.jaegertracing.io/download/#binaries)
2.使用docker
docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
-p 14250:14250 \
-p 14268:14268 \
-p 14269:14269 \
-p 9411:9411 \
jaegertracing/all-in-one:1.49
我是在windows下使用下载的二进制文件启动服务
注: 需要再终端中执行jaeger-all-in-one.exe即可启动服务
[golang接入]
实现gorm的CRUD的链路记录
Demo文件:
gormTracing.go
package gorm_trace import (
"github.com/opentracing/opentracing-go"
tracerLog "github.com/opentracing/opentracing-go/log"
"gorm.io/gorm"
) const (
gormSpanKey = "__gorm_span"
callBackBeforeName = "opentracing:before"
callBackAfterName = "opentracing:after"
) func before(db *gorm.DB) {
// 先从父级spans生成子span
span, _ := opentracing.StartSpanFromContext(db.Statement.Context, "gorm")
// 利用db实例去传递span
db.InstanceSet(gormSpanKey, span)
return
} func after(db *gorm.DB) {
// 从GORM的DB实例中取出span
_span, isExist := db.InstanceGet(gormSpanKey)
if !isExist {
return
} // 断言进行类型转换
span, ok := _span.(opentracing.Span)
if !ok {
return
}
defer span.Finish() // Error
if db.Error != nil {
span.LogFields(tracerLog.Error(db.Error))
} // sql
span.LogFields(tracerLog.String("sql", db.Dialector.Explain(db.Statement.SQL.String(), db.Statement.Vars...)))
return
} type OpentracingPlugin struct{} func (op *OpentracingPlugin) Name() string {
return "opentracingPlugin"
} func (op *OpentracingPlugin) Initialize(db *gorm.DB) (err error) {
// 开始前
db.Callback().Create().Before("gorm:before_create").Register(callBackBeforeName, before)
db.Callback().Query().Before("gorm:query").Register(callBackBeforeName, before)
db.Callback().Delete().Before("gorm:before_delete").Register(callBackBeforeName, before)
db.Callback().Update().Before("gorm:setup_reflect_value").Register(callBackBeforeName, before)
db.Callback().Row().Before("gorm:row").Register(callBackBeforeName, before)
db.Callback().Raw().Before("gorm:raw").Register(callBackBeforeName, before) // 结束后
db.Callback().Create().After("gorm:after_create").Register(callBackAfterName, after)
db.Callback().Query().After("gorm:after_query").Register(callBackAfterName, after)
db.Callback().Delete().After("gorm:after_delete").Register(callBackAfterName, after)
db.Callback().Update().After("gorm:after_update").Register(callBackAfterName, after)
db.Callback().Row().After("gorm:row").Register(callBackAfterName, after)
db.Callback().Raw().After("gorm:raw").Register(callBackAfterName, after)
return
} var _ gorm.Plugin = &OpentracingPlugin{}
测试文件:
package gorm_trace import (
"context"
"fmt"
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
"github.com/uber/jaeger-client-go/config"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"io"
"math/rand"
"strconv"
"sync"
"testing"
"time"
) const dsn = "root:123456@tcp(localhost:3306)/test?charset=utf8mb4&parseTime=True&loc=Local" func initJaeger() (closer io.Closer, err error) {
// 根据配置初始化Tracer 返回Closer
tracer, closer, err := (&config.Configuration{
ServiceName: "gormTracing",
Disabled: false,
Sampler: &config.SamplerConfig{
Type: jaeger.SamplerTypeConst,
// param的值在0到1之间,设置为1则将所有的Operation输出到Reporter
Param: 1,
},
Reporter: &config.ReporterConfig{
LogSpans: true,
LocalAgentHostPort: "localhost:6831",
},
}).NewTracer()
if err != nil {
return
} // 设置全局Tracer - 如果不设置将会导致上下文无法生成正确的Span
opentracing.SetGlobalTracer(tracer)
return
} type Product struct {
gorm.Model
Code string
Price uint
} func Test_GormTracing(t *testing.T) {
closer, err := initJaeger()
if err != nil {
t.Fatal(err)
}
defer closer.Close() db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
_ = db.Use(&OpentracingPlugin{}) // 迁移 schema
_ = db.AutoMigrate(&Product{}) // 生成新的Span - 注意将span结束掉,不然无法发送对应的结果
span := opentracing.StartSpan("gormTracing unit test")
defer span.Finish() // 把生成的Root Span写入到Context上下文,获取一个子Context
ctx := opentracing.ContextWithSpan(context.Background(), span)
session := db.WithContext(ctx) // Create
session.Create(&Product{Code: "D42", Price: 100}) // Read
var product Product
session.First(&product, 1) // 根据整形主键查找
session.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录 // Update - 将 product 的 price 更新为 200
session.Model(&product).Update("Price", 200)
// Update - 更新多个字段
session.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
session.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"}) // Delete - 删除 product
session.Delete(&product, 1)
} func Test_GormTracing2(t *testing.T) {
closer, err := initJaeger()
if err != nil {
t.Fatal(err)
}
defer closer.Close() db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
_ = db.Use(&OpentracingPlugin{}) rand.Seed(time.Now().UnixNano()) //num, wg := 1<<10, &sync.WaitGroup{}
num, wg := 110, &sync.WaitGroup{} wg.Add(num) for i := 0; i < num; i++ {
go func(t int) {
span := opentracing.StartSpan(fmt.Sprintf("gormTracing unit test %d", t))
defer span.Finish() ctx := opentracing.ContextWithSpan(context.Background(), span)
session := db.WithContext(ctx) p := &Product{Code: strconv.Itoa(t), Price: uint(rand.Intn(1 << 10))} session.Create(p) session.First(p, p.ID) session.Delete(p, p.ID) wg.Done()
}(i)
} wg.Wait()
}
[使用]
打开浏览器: http://localhost:16686 即可查看
进行筛选,查看上报的追踪信息

参考:
- https://github.com/avtion/gormTracing
链路追踪之Jaeger的更多相关文章
- [系列] go-gin-api 路由中间件 - Jaeger 链路追踪(五)
概述 首先同步下项目概况: 上篇文章分享了,路由中间件 - 捕获异常,这篇文章咱们分享:路由中间件 - Jaeger 链路追踪. 啥是链路追踪? 我理解链路追踪其实是为微服务架构提供服务的,当一个请求 ...
- [系列] go-gin-api 路由中间件 - Jaeger 链路追踪(六)
[DOC] 概述 首先同步下项目概况: 上篇文章分享了,路由中间件 - Jaeger 链路追踪(理论篇),这篇文章咱们接着分享:路由中间件 - Jaeger 链路追踪(实战篇). 这篇文章,确实让大家 ...
- go-gin-api 路由中间件 - Jaeger 链路追踪
概述 首先同步下项目概况: 上篇文章分享了,路由中间件 - Jaeger 链路追踪(理论篇). 这篇文章咱们分享:路由中间件 - Jaeger 链路追踪(实战篇). 说实话,这篇文章确实让大家久等了, ...
- Jaeger Client Go 链路追踪|入门详解
目录 从何说起 Jaeger 部署 Jaeger 从示例了解 Jaeger Client Go 了解 trace.span tracer 配置 Sampler 配置 Reporter 配置 分布式系统 ...
- 基于Dapper的分布式链路追踪入门——Opencensus+Zipkin+Jaeger
微信搜索公众号 「程序员白泽」,进入白泽的编程知识分享星球 最近做了一些分布式链路追踪有关的东西,写篇文章来梳理一下思路,或许可以帮到想入门的同学.下面我将从原理到demo为大家一一进行讲解,欢迎评论 ...
- go-zero docker-compose 搭建课件服务(八):集成jaeger链路追踪
0.转载 go-zero docker-compose 搭建课件服务(八):集成jaeger链路追踪 0.1源码地址 https://github.com/liuyuede123/go-zero-co ...
- Asp.Net Core&Jaeger实现链路追踪
前言 随着应用愈发复杂,请求的链路也愈发复杂,微服务化下,更是使得不同的服务分布在不同的机器,地域,语言也不尽相同.因此需要借助工具帮助分析,跟踪,定位请求中出现的若干问题,以此来保障服务治理,链路追 ...
- (16)go-micro微服务jaeger链路追踪
目录 一 jaeger链路追踪介绍 什么是链路追踪: 链路追踪主要功能: 二 jaeger链路追踪作用 三 jaeger链路追踪主要特性 四 jaeger链路追踪原理图 1.链路调用原理 2. 一次调 ...
- istio-opentracing链路追踪方案
目录 istio-opentracing链路追踪方案 envoy链路追踪 初始化追踪 跟踪上下文信息 istio链路追踪 链路追踪参数 采样率 jaeger istio中jaeger现状 jaeger ...
- 全链路追踪技术选型:pinpoint vs skywalking
目前分布式链路追踪系统基本都是根据谷歌的<Dapper大规模分布式系统的跟踪系统>这篇论文发展而来,主流的有zipkin,pinpoint,skywalking,cat,jaeger等. ...
随机推荐
- C语言数据的存储
目录 类型的基本归类 整形在内存中的存储 原码.反码.补码 大小端介绍 练习 浮点型在内存中的存储 浮点数存储的例子 浮点数存储规则 类型的基本归类 整形家族: char unsigned char ...
- attention, transformers
这啥呀,慢慢啃 Attention 最初来源于 NLP 机器翻译的 Sequence to Sequence 模型,早先的encoder-decoder结构随着句子长度增加翻译性能会下降,因为模型记不 ...
- SNERT内部集训-WEB
SNERT内部集训-WEB Day1-2 文件上传 靶场搭建 docker安装,docker pull c0ny1/upload-labs,docker run -it -d -p 8080:80 a ...
- JavaScript – Async Iterator & Generator
前言 要看懂这篇请先看下面几篇 JavaScript – Iterator JavaScript – Generator Function JavaScript – Promise JavaScrip ...
- 单片机-XIP-外部闪存就地执行代码
声明:此博文所述我未实践,目的是知识整理. 1. 常说的 "单片机的norflash上可以执行代码 " 这句话该如何理解? CPU做取指.译码.执行. 常说的哪些介质可以执行程序 ...
- 9月《中国数据库行业分析报告》已发布,47页干货带你详览 MySQL 崛起之路!
为了帮助大家及时了解中国数据库行业发展现状.梳理当前数据库市场环境和产品生态等情况,从2022年4月起,墨天轮社区行业分析研究团队出品将持续每月为大家推出最新<中国数据库行业分析报告>,持 ...
- vue3中的vue-18n的table表格标题不动态变化中英文
使用 computed 即可 eg: const columns = computed(() => { return reactive<any>([ { title: proxy.$ ...
- ES6箭头函数和普通函数的区别
书写形式不同,箭头函数的定义方式更加简单 : this指向不同 箭头函数使用父级作用域的this 普通函数执行 window 箭头函数不能使用 new 生成实例对象 : 普通函数的参数是argumen ...
- 四、Spring Boot集成Spring Security之认证流程
二.概要说明 本文主要介绍登录登出业务流程,所以使用基于内存的用户名密码,暂不介绍授权相关内容,后续会详细介绍基于数据库的认证及授权 如何查看基于内存的默认用户名密码 如何配置基于内存的自定义用户名密 ...
- Mongo oplog理解
转载请注明出处: oplog(操作日志)是MongoDB中用于记录所有写操作的日志.它是一个特殊的集合,存储在副本集的主节点中.oplog用于确保副本集中的副节点与主节点的数据保持一致.当主节点执行写 ...