源碼地址
- go sdk:https://github.com/SkyAPM/go2sky
- plugin:https://github.com/SkyAPM/go2sky-plugins 提供了go http、go-restful讹剔、gin等框架的trace接入插件,用于服務(wù)端和客戶端的trace span創(chuàng)建娃肿。
go sdk的基本特性
- 客戶端和服務(wù)端使用grpc雙向stream通信行施。
- 可以設(shè)置采樣率更鲁。默認(rèn)都會(huì)上報(bào)茫多。
- 可以自定義logger绷耍。
- 可以自定義上報(bào)的緩沖通道長(zhǎng)度莽龟,默認(rèn)30000
- 可以自定義服務(wù)實(shí)例上報(bào)的屬性字段。
- 可以自定義服務(wù)實(shí)例標(biāo)識(shí)锨天,默認(rèn)uuid@ipv4。進(jìn)程重啟會(huì)發(fā)生變化剃毒,不建議使用uuid病袄,需要自定義覆蓋。
- 可以自定義trace上報(bào)的reporter赘阀,除grpcReporter以外都是mock益缠、debug、logger等reporter基公,不能用于生產(chǎn)環(huán)境幅慌。如果grpcReporter無(wú)法滿足需要,可以基于接口重寫(xiě)轰豆。
- 提供gin胰伍、go-restful齿诞、go http server的trace插件和go http client的trace功能。
- 一個(gè)進(jìn)程內(nèi)的同一個(gè)trace鏈路上的多個(gè)span(父子span)構(gòu)成一個(gè)segment上報(bào)的骂租。不是單個(gè)span挨個(gè)上報(bào)祷杈。邏輯上看,一個(gè)邏輯segment包含多個(gè)父子span渗饮,構(gòu)成一個(gè)SegmentObject上報(bào)到服務(wù)端但汞。
數(shù)據(jù)結(jié)構(gòu)
spanContext是span的上下文』フ荆跨進(jìn)程通信需要將此對(duì)象序列化到協(xié)議中私蕾,然后從協(xié)議中反序列化出此對(duì)象。
type SpanContext struct {
TraceID string `json:"trace_id"` //traceId
ParentSegmentID string `json:"parent_segment_id"` //父segmentId
ParentService string `json:"parent_service"` //父service
ParentServiceInstance string `json:"parent_service_instance"` //父實(shí)例
ParentEndpoint string `json:"parent_endpoint"` //父endpoint
AddressUsedAtClient string `json:"address_used_at_client"`
ParentSpanID int32 `json:"parent_span_id"` //父spanId
Sample int8 `json:"sample"`
}
defaultSpan記錄span基本信息胡桃。持有tracer踩叭、時(shí)間和spanContext等信息。實(shí)現(xiàn)span接口标捺。
type defaultSpan struct {
Refs []*propagation.SpanContext //跨進(jìn)程通信用的span上下文懊纳。
tracer *Tracer //上報(bào)trace用的client封裝對(duì)象。
StartTime time.Time //span起始時(shí)間
EndTime time.Time //span結(jié)束時(shí)間
OperationName string //span操作名稱(chēng)亡容。http是/method/uri
Peer string //span對(duì)端地址
Layer v3.SpanLayer //span的用途嗤疯。有數(shù)據(jù)庫(kù)、rpc闺兢、http茂缚、mq、緩存屋谭。
ComponentID int32 //創(chuàng)建span的組件ID脚囊。比如5005是http client;5004是http server桐磁。
Tags []*common.KeyStringValuePair //span鍵值對(duì)
Logs []*v3.Log //span核心日志
IsError bool //span是否有錯(cuò)誤悔耘,一般http code不等于200,rpc超時(shí)都需要標(biāo)記error我擂。
SpanType SpanType //span類(lèi)型衬以。入口端用entry、調(diào)用端用exit校摩。
}
segmentContext是segment上下文看峻,主要用于生成spanId,記錄同一個(gè)鏈路父子span的個(gè)數(shù)等衙吩。
- 每個(gè)span都有一個(gè)自己的segmentContext對(duì)象互妓。記錄當(dāng)前spanId、父spanId。
- 同一個(gè)進(jìn)程的同一個(gè)鏈路的不同span(即父子span)的segmentContext對(duì)象不同冯勉,但共用一個(gè)spanId生成器澈蚌、共用同一個(gè)segmentId、共用一個(gè)collect收集器珠闰、共用一個(gè)refNum字段惜浅。可以說(shuō)伏嗜,同一個(gè)進(jìn)程的同一個(gè)鏈路的父子span共用同一個(gè)邏輯segmentContext坛悉。
type SegmentContext struct {
TraceID string //鏈路唯一Id。如果從協(xié)議中解析出SpanContext承绸,則延續(xù)使用裸影。沒(méi)有則隨機(jī)生成UUID。
SegmentID string //段Id军熏。隨機(jī)生成轩猩。父子span共用一個(gè)segmentId
SpanID int32 //關(guān)聯(lián)的spanId
ParentSpanID int32 //關(guān)聯(lián)的span的父spanId
ParentSegmentID string //父段id,就是自身ID荡澎。
collect chan<- ReportedSpan //上報(bào)span的channel通道均践。父子span共用一個(gè)channel通道。
refNum *int32 //當(dāng)前segment包含多少個(gè)span摩幔。
spanIDGenerator *int32 //同一個(gè)segment下spanId的生成器彤委,atomic自增。
FirstSpan Span `json:"-"`
}
segmentSpanImpl組合defaultSpan和SegmentContext或衡,該對(duì)象是真正意義的span焦影。
type segmentSpanImpl struct {
defaultSpan
SegmentContext
}
rootSegmentSpan是根span,組合segmentSpanImpl封断,也就實(shí)現(xiàn)span接口斯辰。進(jìn)程內(nèi)每個(gè)trace鏈路上都有一個(gè)起始的根span,用于進(jìn)程內(nèi)當(dāng)前鏈路上所有span的收尾上報(bào)坡疼。每個(gè)根span創(chuàng)建時(shí)會(huì)啟動(dòng)單獨(dú)的協(xié)程彬呻,循環(huán)接收子span或監(jiān)聽(tīng)trace鏈路結(jié)束信號(hào)。根span重新實(shí)現(xiàn)了span的End接口柄瑰,當(dāng)根span操作end闸氮,不僅結(jié)束當(dāng)前根span(設(shè)置結(jié)束時(shí)間),還會(huì)往done channel發(fā)送信號(hào)狱意,通知接收方開(kāi)始上報(bào)當(dāng)前鏈路的所有span對(duì)象。
type rootSegmentSpan struct {
*segmentSpanImpl
notify <-chan ReportedSpan //接收segmentSpanImpl拯欧,和segmentSpanImpl中的collect是同一個(gè)數(shù)據(jù)通道详囤,for循環(huán)不斷讀取。
segment []ReportedSpan //同一個(gè)進(jìn)程同一個(gè)鏈路的所有segmentSpan的聚合。
doneCh chan int32
}
源碼解析
暫略