手把手教媳妇jaeger简单场景

分布式服务中,通过日志查看错误以及追踪问题,是一件非常痛苦的事情,由此我们可以使用链路追踪来快速定位问题,查看服务调用请用情况,埋点做一些必要的参数标记,此处使用uber开源的jaeger,它完美实现了openTraceing 标准,支持不同语言的客户端,其它的不再赘述了,网上很多的先关学习文档,这里只给出简单的使用场景,为了快速展示应用,直接用docker启动一个服务,jaegertracing/all-in-one,自行参考官网文档


1608554929(1).jpg

打开jaeger-ui的界面如下


1608555027(1).jpg
package main

import (
    "context"
    "fmt"
    "github.com/opentracing/opentracing-go"
    "github.com/uber/jaeger-client-go"
    "github.com/uber/jaeger-client-go/config"
    "io"
    "log"
    "strings"
)


//初始化tracer
func InitTracer() (opentracing.Tracer,io.Closer){
    cfg := &config.Configuration{
        ServiceName: "zzy_jaeger_test",
        Sampler: &config.SamplerConfig{
            Type:                     jaeger.SamplerTypeConst,//固定采样
            Param:                    1,//1全采样,0不采样
        },
        Reporter: &config.ReporterConfig{
            LogSpans:                   true,
            LocalAgentHostPort:         "192.168.1.246:6831",
        },

    }

    //创建tracer
    tracer, closer, err := cfg.NewTracer(config.Logger(jaeger.StdLogger))
    //设置全局tracer
    opentracing.SetGlobalTracer(tracer)
    if err != nil {
        log.Fatal(err)
    }
    return tracer,closer
}

func main() {

    trace, closer := InitTracer()

    defer closer.Close()
    // 创建父span
    spanRoot := trace.StartSpan("rootSpan 埋点")
    // 在函数返回的时候调用finish结束这个span
    defer spanRoot.Finish()
    spanRoot.SetTag("gender","男")
    spanRoot.SetBaggageItem("foo","todo")
    //#创建上下文,使用上下文来传递span
    ctx := opentracing.ContextWithSpan(context.Background(), spanRoot)

    ct := spanRoot.Context().(jaeger.SpanContext)

    fmt.Println("traceID:",ct.TraceID().String())

    // 创建一个childspan
    //childspan:=trace.StartSpan("childSpan 埋点",opentracing.ChildOf(spanRoot.Context()))
    //defer childspan.Finish()
    //# 下面为你的业务代码
    //videoURL := c.DefaultPostForm("url", "")
    //将ctx上下文传到调用的函数里
    ExtractVideo(strings.TrimSpace("媳妇"), ctx)

}

func ExtractVideo(videoURL string, ctx context.Context)  {
    //创建子span
    span, _ := opentracing.StartSpanFromContext(ctx, "childSpan 埋点")
    defer func() {
        span.SetTag("媳妇", videoURL)
        span.Finish()
    }()

}

直接运行,然后在jaeger-ui上查看service,选择最下面的trace,就可以看到刚才的追踪,以及经过的span,点击这个追踪的详情,可以看得到所有设置的tags的值
上边的是最基础简单的例子,好了,下面看看在web服务应用中的使用技巧了

package main

import (
    "fmt"
    "github.com/opentracing/opentracing-go"
    "github.com/uber/jaeger-client-go"
    "github.com/uber/jaeger-client-go/config"
    "io"
    "log"
    "net/http"
)


func NewTrace() (opentracing.Tracer,io.Closer) {

    conf :=  &config.Configuration{
        ServiceName: "trace_srv",
        Sampler: &config.SamplerConfig{
            Type:  jaeger.SamplerTypeConst, //固定采样
            Param: 1,                       //1全采样,0不采样
        },
        Reporter: &config.ReporterConfig{
            LogSpans:           true,
            LocalAgentHostPort: "192.168.1.246:6831",
        },
    }
    trace, closer, err := conf.NewTracer()
    if err != nil {
        log.Fatal(err)
    }
    //设置全局trace,一个微服务对应一个trace的service
    opentracing.SetGlobalTracer(trace)
    return trace, closer
}


//中间件
func tracingMW(next http.Handler) http.HandlerFunc {

    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

        tracer, closer := NewTrace()
        defer closer.Close()
        //以请求的url为operatorName
        rootSpan := tracer.StartSpan(r.URL.Path)
        defer rootSpan.Finish()
        //随便记录一些参数
        rootSpan.SetTag("Method",r.Method)
        rootSpan.SetTag("url",r.URL.Path)
        //打印traceID
        sctx := rootSpan.Context().(jaeger.SpanContext)
        fmt.Println("traceID:",sctx.TraceID().String())
        //利用context传递span在下一个请求中获取chidspan
        ctx := opentracing.ContextWithSpan(r.Context(), rootSpan)
        next.ServeHTTP(w,r.WithContext(ctx))

    })
}

func test(w http.ResponseWriter, r *http.Request)  {
    //从context中拿childspan
    span, _ := opentracing.StartSpanFromContext(r.Context(), "test")
    defer span.Finish()
    ctx := span.Context().(jaeger.SpanContext)
    fmt.Println("traceID:",ctx.TraceID().String())
    span.SetTag("todo","foo")
    fmt.Fprint(w,"haha")

}

func main()  {
    http.HandleFunc("/",tracingMW(http.HandlerFunc(test)))
    http.ListenAndServe(":8080",nil)

}

在web请求中设置一个中间件,在中间件设置rootSpan,然后利用context获取子span,在后续的业务处理中可以一次生成子span,并且为子span名命名
只演示大概的例子,每次中间件都要生成trace,将trace注入容器中保证唯一性,或者直接生成全局唯一的trace实例,根据需要自行扩展

下面演示跨服务(进程)之间实现追踪埋点,先看用http协议跨服务的调用追踪方式,直接在test方法中修改
func test(w http.ResponseWriter, r *http.Request)  {

    url := "http://localhost:8000"
    client := &http.Client{}
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        log.Println(err)
    }

    span, _ := opentracing.StartSpanFromContext(r.Context(), "remote request svc2")
    defer span.Finish()
    span.SetTag("role", "admin")
    span.SetBaggageItem("name", "媳妇")

    ext.SpanKindRPCClient.Set(span)
    ext.HTTPUrl.Set(span, url)
    ext.HTTPMethod.Set(span, "GET")
    span.Tracer().Inject(
        span.Context(),
        opentracing.HTTPHeaders,
        opentracing.HTTPHeadersCarrier(req.Header),
    )

    resp, err := client.Do(req)
    if err != nil {
        log.Println("请求错误:",err)
    }

    log.Println(resp.Status)
    bytes, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Fprint(w,err.Error())
    }

    fmt.Fprint(w,string(bytes))

}

接下来是目标服务的代码

package main

import (
    "fmt"
    "github.com/uber/jaeger-client-go"
    "net/http"
    "log"
    opentracing "github.com/opentracing/opentracing-go"
    "github.com/opentracing/opentracing-go/ext"
    otlog "github.com/opentracing/opentracing-go/log"
    "github.com/uber/jaeger-client-go/config"
)

func fromEnv() (*config.Configuration,error) {

    return  &config.Configuration{
        ServiceName: "svc2",
        Sampler: &config.SamplerConfig{
            Type:  jaeger.SamplerTypeConst, //固定采样
            Param: 1,                       //1全采样,0不采样
        },
        Reporter: &config.ReporterConfig{
            LogSpans:           true,
            LocalAgentHostPort: "192.168.1.246:6831",
        },
    },nil
}

func main(){
    http.HandleFunc("/",test)
    http.ListenAndServe(":8000",nil)
}

func test(w http.ResponseWriter,r *http.Request){
    log.Println(r.Header,r.URL)

    //cfg,err:=config.FromEnv()
    cfg,err:=fromEnv()
    if err!=nil {
        log.Println(err)
    }
    tracer,closer,err:=cfg.NewTracer()
    if err!=nil {
        log.Println(err)
    }
    defer closer.Close()

    spanCtx, _ := tracer.Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header))
    span := tracer.StartSpan("get haha", ext.RPCServerOption(spanCtx))
    defer span.Finish()
    ctx := spanCtx.(jaeger.SpanContext)
    log.Println("traceID:",ctx.TraceID().String())
    log.Println(span.BaggageItem("name"))

    span.LogFields(
        otlog.String("event", "string-format"),
        otlog.String("value", "hello wrold"),
    )
    fmt.Fprint(w,"呵呵,进程的追踪结束")
}

打开浏览器,输入http://localhost:8080/put请求,可以在jaeger-ui中查看请求经过过的span,以及在控制台,可以发现请求的traceID保持一致

1608561179(1).jpg

追踪链路上经过的两个service,继续切换到系统的体系结构图中查看DAG图可以看到服务的调用结构如下:
1608561352(1).jpg

下面演示在grpc的场景下,追踪的方式,和http跨进程调用差不多,直接附上代码

太晚了,明天继续。。。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • 普元推出DevOps系列课程,5分钟秒懂一个知识点,戳“阅读原文”充电5分钟,掌握黑科技。 转载本文需注明出处:微...
    72a1f772fe47阅读 4,500评论 0 0
  • 先从微服务说起 微服务 一个完整的微服务体系至少需要包括: CI / CD 也就是自动化部署 服务发现 统一的PR...
    bysir阅读 11,827评论 5 7
  • 现在越来越多的应用迁移到基于微服务的云原生的架构之上,微服务架构很强大,但是同时也带来了很多的挑战,尤其是如何对应...
    彦帧阅读 1,785评论 0 1
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,471评论 16 22
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,548评论 0 11