亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Jaeger?Client?Go入門(mén)并實(shí)現(xiàn)鏈路追蹤

 更新時(shí)間:2022年03月31日 09:40:32   作者:癡者工良  
這篇文章介紹了Jaeger?Client?Go入門(mén)并實(shí)現(xiàn)鏈路追蹤的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

Jaeger

OpenTracing 是開(kāi)放式分布式追蹤規(guī)范,OpenTracing API 是一致,可表達(dá),與供應(yīng)商無(wú)關(guān)的API,用于分布式跟蹤和上下文傳播。

OpenTracing 的客戶(hù)端庫(kù)以及規(guī)范,可以到 Github 中查看:https://github.com/opentracing/

Jaeger 是 Uber 開(kāi)源的分布式跟蹤系統(tǒng),詳細(xì)的介紹可以自行查閱資料。

部署 Jaeger

這里我們需要部署一個(gè) Jaeger 實(shí)例,以供微服務(wù)以及后面學(xué)習(xí)需要。

使用 Docker 部署很簡(jiǎn)單,只需要執(zhí)行下面一條命令即可:

docker run -d -p 5775:5775/udp -p 16686:16686 -p 14250:14250 -p 14268:14268 jaegertracing/all-in-one:latest

訪問(wèn) 16686 端口,即可看到 UI 界面。

后面我們生成的鏈路追蹤信息會(huì)推送到此服務(wù),而且可以通過(guò) Jaeger UI 查詢(xún)這些追蹤信息。

從示例了解 Jaeger Client Go

這里,我們主要了解一些 Jaeger Client 的接口和結(jié)構(gòu)體,了解一些代碼的使用。

為了讓讀者方便了解 Trace、Span 等,可以看一下這個(gè) Json 的大概結(jié)構(gòu):

        {
            "traceID": "2da97aa33839442e",
            "spans": [
                {
                    "traceID": "2da97aa33839442e",
                    "spanID": "ccb83780e27f016c",
                    "flags": 1,
                    "operationName": "format-string",
                    "references": [...],
                    "tags": [...],
                    "logs": [...],
                    "processID": "p1",
                    "warnings": null
                },
                ... ...
            ],
            "processes": {
                "p1": {
                    "serviceName": "hello-world",
                    "tags": [...]
                },
                "p2": ...,
            "warnings": null
        }

創(chuàng)建一個(gè) client1 的項(xiàng)目,然后引入 Jaeger client 包。

go get -u github.com/uber/jaeger-client-go/

然后引入包

import (
	"github.com/uber/jaeger-client-go"
)

了解 trace、span

鏈路追蹤中的一個(gè)進(jìn)程使用一個(gè) trace 實(shí)例標(biāo)識(shí),每個(gè)服務(wù)或函數(shù)使用一個(gè) span 標(biāo)識(shí),jaeger 包中有個(gè)函數(shù)可以創(chuàng)建空的 trace:

tracer := opentracing.GlobalTracer()	// 生產(chǎn)中不要使用

然后就是調(diào)用鏈中,生成父子關(guān)系的 Span:

func main() {
	tracer := opentracing.GlobalTracer()
	// 創(chuàng)建第一個(gè) span A
	parentSpan := tracer.StartSpan("A")
    defer parentSpan.Finish()		// 可手動(dòng)調(diào)用 Finish()

}
func B(tracer opentracing.Tracer,parentSpan opentracing.Span){
	// 繼承上下文關(guān)系,創(chuàng)建子 span
	childSpan := tracer.StartSpan(
		"B",
		opentracing.ChildOf(parentSpan.Context()),
		)
	defer childSpan.Finish()	// 可手動(dòng)調(diào)用 Finish()
}

每個(gè) span 表示調(diào)用鏈中的一個(gè)結(jié)點(diǎn),每個(gè)結(jié)點(diǎn)都需要明確父 span。

現(xiàn)在,我們知道了,如何生成 trace{span1,span2},且 span1 -> span2 即 span1 調(diào)用 span2,或 span1 依賴(lài)于 span2。

tracer 配置

由于服務(wù)之間的調(diào)用是跨進(jìn)程的,每個(gè)進(jìn)程都有一些特點(diǎn)的標(biāo)記,為了標(biāo)識(shí)這些進(jìn)程,我們需要在上下文間、span 攜帶一些信息。

例如,我們?cè)诎l(fā)起請(qǐng)求的第一個(gè)進(jìn)程中,配置 trace,配置服務(wù)名稱(chēng)等。

// 引入 jaegercfg "github.com/uber/jaeger-client-go/config"
	cfg := jaegercfg.Configuration{
		ServiceName: "client test", // 對(duì)其發(fā)起請(qǐng)求的的調(diào)用鏈,叫什么服務(wù)
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans: true,
		},
	}

Sampler 是客戶(hù)端采樣率配置,可以通過(guò) sampler.type 和 sampler.param 屬性選擇采樣類(lèi)型,后面詳細(xì)聊一下。

Reporter 可以配置如何上報(bào),后面獨(dú)立小節(jié)聊一下這個(gè)配置。

傳遞上下文的時(shí)候,我們可以打印一些日志:

	jLogger := jaegerlog.StdLogger

配置完畢后就可以創(chuàng)建 tracer 對(duì)象了:

	tracer, closer, err := cfg.NewTracer(
		jaegercfg.Logger(jLogger),
	)
	
	defer closer.Close()
	if err != nil {
	}

完整代碼如下:

import (
    "github.com/opentracing/opentracing-go"
	"github.com/uber/jaeger-client-go"
	jaegercfg "github.com/uber/jaeger-client-go/config"
	jaegerlog "github.com/uber/jaeger-client-go/log"
)

func main() {

	cfg := jaegercfg.Configuration{
		ServiceName: "client test", // 對(duì)其發(fā)起請(qǐng)求的的調(diào)用鏈,叫什么服務(wù)
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans: true,
		},
	}

	jLogger := jaegerlog.StdLogger
	tracer, closer, err := cfg.NewTracer(
		jaegercfg.Logger(jLogger),
	)

	defer closer.Close()
	if err != nil {
	}

	// 創(chuàng)建第一個(gè) span A
	parentSpan := tracer.StartSpan("A")
	defer parentSpan.Finish()

	B(tracer,parentSpan)
}

func B(tracer opentracing.Tracer, parentSpan opentracing.Span) {
	// 繼承上下文關(guān)系,創(chuàng)建子 span
	childSpan := tracer.StartSpan(
		"B",
		opentracing.ChildOf(parentSpan.Context()),
	)
	defer childSpan.Finish()
}

啟動(dòng)后:

2021/03/30 11:14:38 Initializing logging reporter
2021/03/30 11:14:38 Reporting span 689df7e83255d05d:75668e8ed5ec61da:689df7e83255d05d:1
2021/03/30 11:14:38 Reporting span 689df7e83255d05d:689df7e83255d05d:0000000000000000:1
2021/03/30 11:14:38 DEBUG: closing tracer
2021/03/30 11:14:38 DEBUG: closing reporter

Sampler 配置

sampler 配置代碼示例:

		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		}

這個(gè) sampler 可以使用 jaegercfg.SamplerConfig,通過(guò) typeparam 兩個(gè)字段來(lái)配置采樣器。

為什么要配置采樣器?因?yàn)榉?wù)中的請(qǐng)求千千萬(wàn)萬(wàn),如果每個(gè)請(qǐng)求都要記錄追蹤信息并發(fā)送到 Jaeger 后端,那么面對(duì)高并發(fā)時(shí),記錄鏈路追蹤以及推送追蹤信息消耗的性能就不可忽視,會(huì)對(duì)系統(tǒng)帶來(lái)較大的影響。當(dāng)我們配置 sampler 后,jaeger 會(huì)根據(jù)當(dāng)前配置的采樣策略做出采樣行為。

詳細(xì)可以參考:https://www.jaegertracing.io/docs/1.22/sampling/

jaegercfg.SamplerConfig 結(jié)構(gòu)體中的字段 Param 是設(shè)置采樣率或速率,要根據(jù) Type 而定。

下面對(duì)其關(guān)系進(jìn)行說(shuō)明:

TypeParam說(shuō)明
"const"0或1采樣器始終對(duì)所有 tracer 做出相同的決定;要么全部采樣,要么全部不采樣
"probabilistic"0.0~1.0采樣器做出隨機(jī)采樣決策,Param 為采樣概率
"ratelimiting"N采樣器一定的恒定速率對(duì)tracer進(jìn)行采樣,Param=2.0,則限制每秒采集2條
"remote"無(wú)采樣器請(qǐng)咨詢(xún)Jaeger代理以獲取在當(dāng)前服務(wù)中使用的適當(dāng)采樣策略。

sampler.Type="remote"/sampler.Type=jaeger.SamplerTypeRemote 是采樣器的默認(rèn)值,當(dāng)我們不做配置時(shí),會(huì)從 Jaeger 后端中央配置甚至動(dòng)態(tài)地控制服務(wù)中的采樣策略。

Reporter 配置

看一下 ReporterConfig 的定義。

type ReporterConfig struct {
    QueueSize                  int `yaml:"queueSize"`
    BufferFlushInterval        time.Duration
    LogSpans                   bool   `yaml:"logSpans"`
    LocalAgentHostPort         string `yaml:"localAgentHostPort"`
    DisableAttemptReconnecting bool   `yaml:"disableAttemptReconnecting"`
    AttemptReconnectInterval   time.Duration
    CollectorEndpoint          string            `yaml:"collectorEndpoint"`
    User                       string            `yaml:"user"`
    Password                   string            `yaml:"password"`
    HTTPHeaders                map[string]string `yaml:"http_headers"`
}

Reporter 配置客戶(hù)端如何上報(bào)追蹤信息的,所有字段都是可選的。

這里我們介紹幾個(gè)常用的配置字段。

  • QUEUESIZE,設(shè)置隊(duì)列大小,存儲(chǔ)采樣的 span 信息,隊(duì)列滿(mǎn)了后一次性發(fā)送到 jaeger 后端;defaultQueueSize 默認(rèn)為 100;

  • BufferFlushInterval 強(qiáng)制清空、推送隊(duì)列時(shí)間,對(duì)于流量不高的程序,隊(duì)列可能長(zhǎng)時(shí)間不能滿(mǎn),那么設(shè)置這個(gè)時(shí)間,超時(shí)可以自動(dòng)推送一次。對(duì)于高并發(fā)的情況,一般隊(duì)列很快就會(huì)滿(mǎn)的,滿(mǎn)了后也會(huì)自動(dòng)推送。默認(rèn)為1秒。

  • LogSpans 是否把 Log 也推送,span 中可以攜帶一些日志信息。

  • LocalAgentHostPort 要推送到的 Jaeger agent,默認(rèn)端口 6831,是 Jaeger 接收壓縮格式的 thrift 協(xié)議的數(shù)據(jù)端口。

  • CollectorEndpoint 要推送到的 Jaeger Collector,用 Collector 就不用 agent 了。

例如通過(guò) http 上傳 trace:

		Reporter: &jaegercfg.ReporterConfig{
			LogSpans:           true,
			CollectorEndpoint: "http://127.0.0.1:14268/api/traces",
		},

據(jù)黑洞大佬的提示,HTTP 走的就是 thrift,而 gRPC 是 .NET 特供,所以 reporter 格式只有一種,而且填寫(xiě) CollectorEndpoint,我們注意要填寫(xiě)完整的信息。

完整代碼測(cè)試:

import (
	"bufio"
    "github.com/opentracing/opentracing-go"
	"github.com/uber/jaeger-client-go"
	jaegercfg "github.com/uber/jaeger-client-go/config"
	jaegerlog "github.com/uber/jaeger-client-go/log"
	"os"
)

func main() {

	var cfg = jaegercfg.Configuration{
		ServiceName: "client test", // 對(duì)其發(fā)起請(qǐng)求的的調(diào)用鏈,叫什么服務(wù)
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans:           true,
			CollectorEndpoint: "http://127.0.0.1:14268/api/traces",
		},
	}

	jLogger := jaegerlog.StdLogger
	tracer, closer, _ := cfg.NewTracer(
		jaegercfg.Logger(jLogger),
	)

	// 創(chuàng)建第一個(gè) span A
	parentSpan := tracer.StartSpan("A")
	// 調(diào)用其它服務(wù)
	B(tracer, parentSpan)
	// 結(jié)束 A
	parentSpan.Finish()
	// 結(jié)束當(dāng)前 tracer
	closer.Close()

	reader := bufio.NewReader(os.Stdin)
	_, _ = reader.ReadByte()
}
func B(tracer opentracing.Tracer, parentSpan opentracing.Span) {
	// 繼承上下文關(guān)系,創(chuàng)建子 span
	childSpan := tracer.StartSpan(
		"B",
		opentracing.ChildOf(parentSpan.Context()),
	)
	defer childSpan.Finish()
}

運(yùn)行后輸出結(jié)果:

2021/03/30 15:04:15 Initializing logging reporter
2021/03/30 15:04:15 Reporting span 715e0af47c7d9acb:7dc9a6b568951e4f:715e0af47c7d9acb:1
2021/03/30 15:04:15 Reporting span 715e0af47c7d9acb:715e0af47c7d9acb:0000000000000000:1
2021/03/30 15:04:15 DEBUG: closing tracer
2021/03/30 15:04:15 DEBUG: closing reporter
2021/03/30 15:04:15 DEBUG: flushed 1 spans
2021/03/30 15:04:15 DEBUG: flushed 1 spans

打開(kāi) Jaeger UI,可以看到已經(jīng)推送完畢(http://127.0.0.1:16686)。

上傳的trace

這時(shí),我們可以抽象代碼代碼示例:

func CreateTracer(servieName string) (opentracing.Tracer, io.Closer, error) {
	var cfg = jaegercfg.Configuration{
		ServiceName: servieName,
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans:          true,
			// 按實(shí)際情況替換你的 ip
			CollectorEndpoint: "http://127.0.0.1:14268/api/traces",
		},
	}

	jLogger := jaegerlog.StdLogger
	tracer, closer, err := cfg.NewTracer(
		jaegercfg.Logger(jLogger),
	)
	return tracer, closer, err
}

這樣可以復(fù)用代碼,調(diào)用函數(shù)創(chuàng)建一個(gè)新的 tracer。這個(gè)記下來(lái),后面要用。

分布式系統(tǒng)與span

前面介紹了如何配置 tracer 、推送數(shù)據(jù)到 Jaeger Collector,接下來(lái)我們聊一下 Span。請(qǐng)看圖。

下圖是一個(gè)由用戶(hù) X 請(qǐng)求發(fā)起的,穿過(guò)多個(gè)服務(wù)的分布式系統(tǒng),A、B、C、D、E 表示不同的子系統(tǒng)或處理過(guò)程。

在這個(gè)圖中, A 是前端,B、C 是中間層、D、E 是 C 的后端。這些子系統(tǒng)通過(guò) rpc 協(xié)議連接,例如 gRPC。

一個(gè)簡(jiǎn)單實(shí)用的分布式鏈路追蹤系統(tǒng)的實(shí)現(xiàn),就是對(duì)服務(wù)器上每一次請(qǐng)求以及響應(yīng)收集跟蹤標(biāo)識(shí)符(message identifiers)和時(shí)間戳(timestamped events)。

這里,我們只需要記住,從 A 開(kāi)始,A 需要依賴(lài)多個(gè)服務(wù)才能完成任務(wù),每個(gè)服務(wù)可能是一個(gè)進(jìn)程,也可能是一個(gè)進(jìn)程中的另一個(gè)函數(shù)。這個(gè)要看你代碼是怎么寫(xiě)的。后面會(huì)詳細(xì)說(shuō)一下如何定義這種關(guān)系,現(xiàn)在大概了解一下即可。

怎么調(diào)、怎么傳

如果有了解過(guò) Jaeger 或讀過(guò) 分布式鏈路追蹤框架的基本實(shí)現(xiàn)原理 ,那么已經(jīng)大概了解的 Jaeger 的工作原理。

jaeger 是分布式鏈路追蹤工具,如果不用在跨進(jìn)程上,那么 Jaeger 就失去了意義。而微服務(wù)中跨進(jìn)程調(diào)用,一般有 HTTP 和 gRPC 兩種,下面將來(lái)講解如何在 HTTP、gPRC 調(diào)用中傳遞 Jaeger 的 上下文。

HTTP,跨進(jìn)程追蹤

A、B 兩個(gè)進(jìn)程,A 通過(guò) HTTP 調(diào)用 B 時(shí),通過(guò) Http Header 攜帶 trace 信息(稱(chēng)為上下文),然后 B 進(jìn)程接收后,解析出來(lái),在創(chuàng)建 trace 時(shí)跟傳遞而來(lái)的 上下文關(guān)聯(lián)起來(lái)。

一般使用中間件來(lái)處理別的進(jìn)程傳遞而來(lái)的上下文。inject 函數(shù)打包上下文到 Header 中,而 extract 函數(shù)則將其解析出來(lái)。

這里我們分為兩步,第一步從 A 進(jìn)程中傳遞上下文信息到 B 進(jìn)程,為了方便演示已經(jīng)實(shí)踐,我們使用 client-webserver 的形式,編寫(xiě)代碼。

客戶(hù)端

在 A 進(jìn)程新建一個(gè)方法:

// 請(qǐng)求遠(yuǎn)程服務(wù),獲得用戶(hù)信息
func GetUserInfo(tracer opentracing.Tracer, parentSpan opentracing.Span) {
	// 繼承上下文關(guān)系,創(chuàng)建子 span
	childSpan := tracer.StartSpan(
		"B",
		opentracing.ChildOf(parentSpan.Context()),
	)

	url := "http://127.0.0.1:8081/Get?username=癡者工良"
	req,_ := http.NewRequest("GET", url, nil)
	// 設(shè)置 tag,這個(gè) tag 我們后面講
	ext.SpanKindRPCClient.Set(childSpan)
	ext.HTTPUrl.Set(childSpan, url)
	ext.HTTPMethod.Set(childSpan, "GET")
	tracer.Inject(childSpan.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))
	resp, _ := http.DefaultClient.Do(req)
	_ = resp 	// 丟掉
	defer childSpan.Finish()
}

然后復(fù)用前面提到的 CreateTracer 函數(shù)。

main 函數(shù)改成:

func main() {
	tracer, closer, _ := CreateTracer("UserinfoService")
	// 創(chuàng)建第一個(gè) span A
	parentSpan := tracer.StartSpan("A")
	// 調(diào)用其它服務(wù)
	GetUserInfo(tracer, parentSpan)
	// 結(jié)束 A
	parentSpan.Finish()
	// 結(jié)束當(dāng)前 tracer
	closer.Close()

	reader := bufio.NewReader(os.Stdin)
	_, _ = reader.ReadByte()
}

完整代碼可參考:https://github.com/whuanle/DistributedTracingGo/issues/1

Web 服務(wù)端

服務(wù)端我們使用 gin 來(lái)搭建。

新建一個(gè) go 項(xiàng)目,在 main.go 目錄中,執(zhí)行 go get -u github.com/gin-gonic/gin。

創(chuàng)建一個(gè)函數(shù),該函數(shù)可以從創(chuàng)建一個(gè) tracer,并且繼承其它進(jìn)程傳遞過(guò)來(lái)的上下文信息。

// 從上下文中解析并創(chuàng)建一個(gè)新的 trace,獲得傳播的 上下文(SpanContext)
func CreateTracer(serviceName string, header http.Header) (opentracing.Tracer,opentracing.SpanContext, io.Closer, error) {
	var cfg = jaegercfg.Configuration{
		ServiceName: serviceName,
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans: true,
			// 按實(shí)際情況替換你的 ip
			CollectorEndpoint: "http://127.0.0.1:14268/api/traces",
		},
	}

	jLogger := jaegerlog.StdLogger
	tracer, closer, err := cfg.NewTracer(
		jaegercfg.Logger(jLogger),
	)
	// 繼承別的進(jìn)程傳遞過(guò)來(lái)的上下文
	spanContext, _ := tracer.Extract(opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(header))
	return tracer, spanContext, closer, err
}

為了解析 HTTP 傳遞而來(lái)的 span 上下文,我們需要通過(guò)中間件來(lái)解析了處理一些細(xì)節(jié)。

func UseOpenTracing() gin.HandlerFunc {
	handler := func(c *gin.Context) {
		// 使用 opentracing.GlobalTracer() 獲取全局 Tracer
		tracer,spanContext, closer, _ := CreateTracer("userInfoWebService", c.Request.Header)
		defer closer.Close()
		// 生成依賴(lài)關(guān)系,并新建一個(gè) span、
		// 這里很重要,因?yàn)樯闪? References []SpanReference 依賴(lài)關(guān)系
		startSpan:= tracer.StartSpan(c.Request.URL.Path,ext.RPCServerOption(spanContext))
		defer startSpan.Finish()

		// 記錄 tag
		// 記錄請(qǐng)求 Url
		ext.HTTPUrl.Set(startSpan, c.Request.URL.Path)
		// Http Method
		ext.HTTPMethod.Set(startSpan, c.Request.Method)
		// 記錄組件名稱(chēng)
		ext.Component.Set(startSpan, "Gin-Http")

		// 在 header 中加上當(dāng)前進(jìn)程的上下文信息
		c.Request=c.Request.WithContext(opentracing.ContextWithSpan(c.Request.Context(),startSpan))
		// 傳遞給下一個(gè)中間件
		c.Next()
		// 繼續(xù)設(shè)置 tag
		ext.HTTPStatusCode.Set(startSpan, uint16(c.Writer.Status()))
	}

	return handler
}

別忘記了 API 服務(wù):

func GetUserInfo(ctx *gin.Context) {
	userName := ctx.Param("username")
	fmt.Println("收到請(qǐng)求,用戶(hù)名稱(chēng)為:", userName)
	ctx.String(http.StatusOK, "他的博客是 https://whuanle.cn")
}

然后是 main 方法:

func main() {
	r := gin.Default()
	// 插入中間件處理
	r.Use(UseOpenTracing())
	r.GET("/Get",GetUserInfo)
	r.Run("0.0.0.0:8081") // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

完整代碼可參考:https://github.com/whuanle/DistributedTracingGo/issues/2

分別啟動(dòng) webserver、client,會(huì)發(fā)現(xiàn)打印日志。并且打開(kāi) jaerger ui 界面,會(huì)出現(xiàn)相關(guān)的追蹤信息。

Jaeger追蹤記錄

Tag 、 Log 和 Ref

Jaeger 的鏈路追蹤中,可以攜帶 Tag 和 Log,他們都是鍵值對(duì)的形式:

                        {
                            "key": "http.method",
                            "type": "string",
                            "value": "GET"
                        },

Tag 設(shè)置方法是 ext.xxxx,例如 :

ext.HTTPUrl.Set(startSpan, c.Request.URL.Path)

因?yàn)?opentracing 已經(jīng)規(guī)定了所有的 Tag 類(lèi)型,所以我們只需要調(diào)用 ext.xxx.Set() 設(shè)置即可。

前面寫(xiě)示例的時(shí)候忘記把日志也加一下了。。。日志其實(shí)很簡(jiǎn)單的,通過(guò) span 對(duì)象調(diào)用函數(shù)即可設(shè)置。

示例(在中間件里面加一下):

        startSpan.LogFields(
            log.String("event", "soft error"),
            log.String("type", "cache timeout"),
            log.Int("waited.millis", 1500))

ref 就是多個(gè) span 之間的關(guān)系。span 可以是跨進(jìn)程的,也可以是一個(gè)進(jìn)程內(nèi)的不同函數(shù)中的。

其中 span 的依賴(lài)關(guān)系表示示例:

                    "references": [
                        {
                            "refType": "CHILD_OF",
                            "traceID": "33ba35e7cc40172c",
                            "spanID": "1c7826fa185d1107"
                        }]

spanID 為其依賴(lài)的父 span。

可以看下面這張圖。

一個(gè)進(jìn)程中的 tracer 可以包裝一些代碼和操作,為多個(gè) span 生成一些信息,或創(chuàng)建父子關(guān)系。

而 遠(yuǎn)程請(qǐng)求中傳遞的是 SpanContext,傳遞后,遠(yuǎn)程服務(wù)也創(chuàng)建新的 tracer,然后從 SpanContext 生成 span 依賴(lài)關(guān)系。

子 span 中,其 reference 列表中,會(huì)帶有 父 span 的 span id。

span傳播

到此這篇關(guān)于Jaeger Client Go入門(mén)并實(shí)現(xiàn)鏈路追蹤的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 如何利用Golang寫(xiě)出高并發(fā)代碼詳解

    如何利用Golang寫(xiě)出高并發(fā)代碼詳解

    今天領(lǐng)導(dǎo)問(wèn)起為什么用Golang,同事回答語(yǔ)法簡(jiǎn)單,語(yǔ)言新,支持高并發(fā)。那高并發(fā)到底如何實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于如何利用Golang寫(xiě)出高并發(fā)代碼的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-09-09
  • GoLang中Strconv庫(kù)有哪些常用方法

    GoLang中Strconv庫(kù)有哪些常用方法

    這篇文章主要介紹了GoLang中Strconv庫(kù)有哪些常用方法,strconv庫(kù)實(shí)現(xiàn)了基本數(shù)據(jù)類(lèi)型與其字符串表示的轉(zhuǎn)換,主要有以下常用函數(shù):?Atoi()、Itia()、parse系列、format系列、append系列
    2023-01-01
  • Golang壓縮Jpeg圖片和PNG圖片的操作

    Golang壓縮Jpeg圖片和PNG圖片的操作

    這篇文章主要介紹了Golang壓縮Jpeg圖片和PNG圖片的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Golang排列組合算法問(wèn)題之全排列實(shí)現(xiàn)方法

    Golang排列組合算法問(wèn)題之全排列實(shí)現(xiàn)方法

    這篇文章主要介紹了Golang排列組合算法問(wèn)題之全排列實(shí)現(xiàn)方法,涉及Go語(yǔ)言針對(duì)字符串的遍歷及排列組合相關(guān)操作技巧,需要的朋友可以參考下
    2017-01-01
  • 詳解go-zero如何使用validator進(jìn)行參數(shù)校驗(yàn)

    詳解go-zero如何使用validator進(jìn)行參數(shù)校驗(yàn)

    這篇文章主要介紹了如何使用validator庫(kù)做參數(shù)校驗(yàn)的一些十分實(shí)用的使用技巧,包括翻譯校驗(yàn)錯(cuò)誤提示信息、自定義提示信息的字段名稱(chēng)、自定義校驗(yàn)方法等,感興趣的可以了解下
    2024-01-01
  • Go語(yǔ)言快速入門(mén)圖文教程

    Go語(yǔ)言快速入門(mén)圖文教程

    Go是 Goolge 開(kāi)發(fā)的一種靜態(tài)型、編譯型、并發(fā)型,并具有垃圾回收功能的語(yǔ)言,Go 語(yǔ)言上手非常容易,它的風(fēng)格類(lèi)似于 C 語(yǔ)言,Go 語(yǔ)言號(hào)稱(chēng)是互聯(lián)網(wǎng)時(shí)代的 C 語(yǔ)言,那么它到底有多火呢,一起看看吧
    2021-05-05
  • Golang flag包的具體使用

    Golang flag包的具體使用

    本文主要介紹了Golang flag包的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • 深入Go goroutine理解

    深入Go goroutine理解

    這篇文章主要介紹了深入Go goroutine理解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02
  • Go語(yǔ)言中如何實(shí)現(xiàn)并發(fā)

    Go語(yǔ)言中如何實(shí)現(xiàn)并發(fā)

    Go的并發(fā)機(jī)制通過(guò)協(xié)程和通道的簡(jiǎn)單性和高效性,使得編寫(xiě)并發(fā)代碼變得相對(duì)容易,這種并發(fā)模型被廣泛用于構(gòu)建高性能的網(wǎng)絡(luò)服務(wù)、并行處理任務(wù)和其他需要有效利用多核處理器的應(yīng)用程序,這篇文章主要介紹了在Go中如何實(shí)現(xiàn)并發(fā),需要的朋友可以參考下
    2023-09-09
  • Go Println和Printf的區(qū)別詳解

    Go Println和Printf的區(qū)別詳解

    這篇文章主要介紹了Go Println和Printf的區(qū)別詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12

最新評(píng)論