源码地址
- go sdk:https://github.com/SkyAPM/go2sky
- plugin:https://github.com/SkyAPM/go2sky-plugins 提供了go http、go-restful、gin等框架的trace接入插件,用于服务端和客户端的trace span创建。
go sdk的基本特性
- 客户端和服务端使用grpc双向stream通信。
- 可以设置采样率。默认都会上报。
- 可以自定义logger。
- 可以自定义上报的缓冲通道长度,默认30000
- 可以自定义服务实例上报的属性字段。
- 可以自定义服务实例标识,默认uuid@ipv4。进程重启会发生变化,不建议使用uuid,需要自定义覆盖。
- 可以自定义trace上报的reporter,除grpcReporter以外都是mock、debug、logger等reporter,不能用于生产环境。如果grpcReporter无法满足需要,可以基于接口重写。
- 提供gin、go-restful、go http server的trace插件和go http client的trace功能。
- 一个进程内的同一个trace链路上的多个span(父子span)构成一个segment上报的。不是单个span挨个上报。逻辑上看,一个逻辑segment包含多个父子span,构成一个SegmentObject上报到服务端。
数据结构
spanContext是span的上下文。跨进程通信需要将此对象序列化到协议中,然后从协议中反序列化出此对象。
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"` //父实例
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、时间和spanContext等信息。实现span接口。
type defaultSpan struct {
Refs []*propagation.SpanContext //跨进程通信用的span上下文。
tracer *Tracer //上报trace用的client封装对象。
StartTime time.Time //span起始时间
EndTime time.Time //span结束时间
OperationName string //span操作名称。http是/method/uri
Peer string //span对端地址
Layer v3.SpanLayer //span的用途。有数据库、rpc、http、mq、缓存。
ComponentID int32 //创建span的组件ID。比如5005是http client;5004是http server。
Tags []*common.KeyStringValuePair //span键值对
Logs []*v3.Log //span核心日志
IsError bool //span是否有错误,一般http code不等于200,rpc超时都需要标记error。
SpanType SpanType //span类型。入口端用entry、调用端用exit。
}
segmentContext是segment上下文,主要用于生成spanId,记录同一个链路父子span的个数等。
- 每个span都有一个自己的segmentContext对象。记录当前spanId、父spanId。
- 同一个进程的同一个链路的不同span(即父子span)的segmentContext对象不同,但共用一个spanId生成器、共用同一个segmentId、共用一个collect收集器、共用一个refNum字段。可以说,同一个进程的同一个链路的父子span共用同一个逻辑segmentContext。
type SegmentContext struct {
TraceID string //链路唯一Id。如果从协议中解析出SpanContext,则延续使用。没有则随机生成UUID。
SegmentID string //段Id。随机生成。父子span共用一个segmentId
SpanID int32 //关联的spanId
ParentSpanID int32 //关联的span的父spanId
ParentSegmentID string //父段id,就是自身ID。
collect chan<- ReportedSpan //上报span的channel通道。父子span共用一个channel通道。
refNum *int32 //当前segment包含多少个span。
spanIDGenerator *int32 //同一个segment下spanId的生成器,atomic自增。
FirstSpan Span `json:"-"`
}
segmentSpanImpl组合defaultSpan和SegmentContext,该对象是真正意义的span。
type segmentSpanImpl struct {
defaultSpan
SegmentContext
}
rootSegmentSpan是根span,组合segmentSpanImpl,也就实现span接口。进程内每个trace链路上都有一个起始的根span,用于进程内当前链路上所有span的收尾上报。每个根span创建时会启动单独的协程,循环接收子span或监听trace链路结束信号。根span重新实现了span的End接口,当根span操作end,不仅结束当前根span(设置结束时间),还会往done channel发送信号,通知接收方开始上报当前链路的所有span对象。
type rootSegmentSpan struct {
*segmentSpanImpl
notify <-chan ReportedSpan //接收segmentSpanImpl,和segmentSpanImpl中的collect是同一个数据通道,for循环不断读取。
segment []ReportedSpan //同一个进程同一个链路的所有segmentSpan的聚合。
doneCh chan int32
}
源码解析
暂略
有疑问加站长微信联系(非本文作者)