链路追踪之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等. ...
随机推荐
- MYSQL数据库备份还原,并还原到最新状态(mysqldump)
启用二进制日志文件 vim /etc/my.cnf 配置文件位置及文件名根据实际情况确定<br>sql_log_bin=on|off:是否记录二进制日志,默认为on 在需要的时候设置为of ...
- Playwright 源码 BrowserType
playwright-java 的 Browser.BrowserContext.Page 挺好理解的,唯独这厮,就有一丢丢 -- package com.microsoft.playwright; ...
- C++源码中司空见惯的PIMPL是什么?
前言: C++源码中司空见惯的PIMPL是什么?用原始指针.std::unique_ptr和std::shared_ptr指向Implementation,会有什么不同?优缺点是什么?读完这篇文章,相 ...
- c++ push_back()和emplace_back()区别
c++ push_back()和emplace_back()区别 References C++中push_back和emplace_back的区别 push_back v.s. emplace_bac ...
- Adobe Acrobat XI Pro 打开pdf报错 109
事件起因: 某同事在使用 Adobe Acrobat XI Pro 打开pdf文件时,会偶发性的报错 "处理页面时发生错误.读取本文当时出现问题(109)." 解决办法: 在网 ...
- 在C#中使用适配器Adapter模式和扩展方法解决面向的对象设计问题
之前有阵子在业余时间拓展自己的一个游戏框架,结果在实现的过程中发现一个设计问题.这个游戏框架基于MonoGame实现,在MonoGame中,所有的材质渲染(Texture Rendering)都是通过 ...
- php获取支付宝用户信息
php获取支付宝用户信息 一:创建应用 要在您的应用中使用支付宝开放产品的接口能力: 您需要先去蚂蚁金服开放平台(open.alipay.com),在开发者中心创建登记您的应用,此时您将获得应用唯一标 ...
- 38. data为什么是一个函数
vue中的data为什么是返回对象的函数,而不是直接使用对象形式 : 我们复用组件的时候,要求每一份data数据之间是独立的,不能互相影响,如果写成对象的形式所有的组件使用一份data数据 ,如果使用 ...
- kotlin更多语言结构——>反射
类引用 最基本的反射功能是获取 Kotlin 类的运行时引用.要获取对静态已知的 Kotlin 类的引用,可以使用 类字面值 语法 val c = MyClass::class 请注意,Kotlin ...
- 开源之夏 2022 重磅来袭!欢迎报名 KubeSphere 社区项目!
活动简介 "开源之夏(英文简称 OSPP)"是中科院软件所"开源软件供应链点亮计划"指导下的系列暑期活动,由软件所与 openEuler 社区共同主办. 开源之 ...