-
Notifications
You must be signed in to change notification settings - Fork 0
/
tracer.go
263 lines (221 loc) · 7.16 KB
/
tracer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
package trace
import (
"fmt"
"io"
"log"
"os"
"strconv"
"strings"
"sync"
"time"
"github.com/aluka-7/utils"
)
var _tracer Tracer = noopTracer{}
// BuiltinFormat 用于在"trace"包中划分与Tracer.Inject()和Tracer.Extract()方法一起使用的值。
type BuiltinFormat byte
const (
// FosTraceID 跟踪键
FosTraceID = "fos-trace-id"
FosTraceDebug = "fos-trace-debug"
flagSampled = 0x01
flagDebug = 0x02
maxLevel = 64
// 硬码重置概率为0.00025, 1/4000
probability = 0.00025
// 支持格式列表:
// HTTPFormat 将Trace表示为HTTP标头字符串对.
// HTTPFormat格式要求键和值按原样作为HTTP标头有效(即,字符大小写可能不稳定,并且键中不允许使用特殊字符,值应转义URL,等等).
// 载体必须是"http.Header".
HTTPFormat BuiltinFormat = iota
// GRPCFormat 承运人必须是`google.golang.org/grpc/metadata.MD`.
GRPCFormat
)
// Config config.
type Config struct {
// 报告网络,例如:Unix,TCP,UDP
Network string `json:"network"`
// 对于TCP和UDP网络,地址的格式为“ host:port”。
// 对于Unix网络,该地址必须是文件系统路径。
Addr string `json:"address"`
// 报告超时
Timeout utils.Duration `json:"timeout"`
// DisableSample
DisableSample bool `json:"disable_sample"`
// ProtocolVersion
ProtocolVersion int32 `json:"protocol_version"`
// Probability probability sampling
Probability float32
}
// Trace trace common interface.
type Trace interface {
// TraceId 返回当前跟踪ID.
TraceId() string
// Fork 用客户端跟踪派生一个跟踪。
Fork(serviceName, operationName string) Trace
Follow(serviceName, operationName string) Trace
// Finish 当跟踪完成时调用它.
Finish(err *error)
// Scan扫描跟踪信息。
// 不推荐使用:不推荐使用Scan方法,请使用Inject代替Scan
// Scan(ti *Info)
// SetTag 添加跟踪标签。
//
// 如果为`key`设置了预先存在的标签,则该标签将被覆盖。
//
// 标记值可以是数字类型,字符串或布尔值.
// 其他标记值类型的行为在OpenTracing级别上未定义。
// 如果跟踪系统不知道如何处理特定的值类型,则可以忽略该标签,但不要惊慌。
// 注意当前仅支持旧标签:TagAnnotation TagAddress TagComment other将被忽略
SetTag(tags ...Tag) Trace
//SetLog LogFields是一种有效且经过类型检查的方式来记录key:value 注意当前不支持
SetLog(logs ...LogField) Trace
// Visit 跟踪访问k-v对,并分别为fn.
Visit(fn func(k, v string))
// SetTitle 重置跟踪标题
SetTitle(title string)
}
// Tracer 是用于跟踪创建和传播的简单,轻界面.
type Tracer interface {
// New trace instance with given title.
New(operationName string, opts ...Option) Trace
// Inject 接收Trace实例,并注入它以便在`carrier`中传播.
// 载体的实际类型取决于格式的值.
Inject(t Trace, format interface{}, carrier interface{}) error
// Extract 返回给定`format`和`carrier`的Trace实例.
// 如果未找到跟踪,则返回`ErrTraceNotFound`.
Extract(format interface{}, carrier interface{}) (Trace, error)
}
// Init init trace report.
func Init(serviceName string, tags []Tag, cfg *Config) {
fmt.Println("Loading FoChange Trace Engine ver:0.9.9")
report := newReport(cfg.Network, cfg.Addr, time.Duration(cfg.Timeout), cfg.ProtocolVersion)
SetGlobalTracer(NewTracer(serviceName, tags, report, cfg.DisableSample))
}
// SetGlobalTracer SetGlobalTracer
func SetGlobalTracer(tracer Tracer) {
fmt.Println("Loading FoChange Set Global Tracer")
_tracer = tracer
}
// NewTracer new a tracer.
func NewTracer(serviceName string, tags []Tag, report reporter, disableSample bool) Tracer {
sampler := newSampler(probability)
stdLog := log.New(os.Stderr, "trace", log.LstdFlags)
return &dapper{
serviceName: serviceName,
disableSample: disableSample,
propagators: map[interface{}]propagator{HTTPFormat: httpPropagator{}, GRPCFormat: gRpcPropagator{}},
reporter: report,
sampler: sampler,
tags: tags,
pool: &sync.Pool{New: func() interface{} { return new(Span) }},
stdLog: stdLog,
}
}
var defaultOption = option{}
type option struct {
Debug bool
}
// Option dapper Option
type Option func(*option)
// EnableDebug enable debug mode
func EnableDebug() Option {
return func(opt *option) {
opt.Debug = true
}
}
// New trace instance with given operationName.
func New(operationName string, opts ...Option) Trace {
return _tracer.New(operationName, opts...)
}
// Inject 接收Trace实例,并将其注入以在`carrier`中传播.载体的实际类型取决于format的值.
func Inject(t Trace, format interface{}, carrier interface{}) error {
return _tracer.Inject(t, format, carrier)
}
// Extract 返回给定`format`和`carrier'的Trace实例. 如果未找到跟踪,则返回`ErrTraceNotFound`.
func Extract(format interface{}, carrier interface{}) (Trace, error) {
return _tracer.Extract(format, carrier)
}
// Close trace flush data.
func Close() error {
if closer, ok := _tracer.(io.Closer); ok {
return closer.Close()
}
return nil
}
// SpanContext实现opentracing.SpanContext
type spanContext struct {
// TraceId 表示跟踪的全局唯一Id;通常生成为随机数.
TraceId uint64
// SpanId 表示范围ID,在其跟踪范围内必须是唯一的,但不必是全局唯一的.
SpanId uint64
// ParentId 是指父范围的Id;如果当前范围是根范围,则应为0.
ParentId uint64
// Flags 是包含诸如“采样”和“调试”之类的位图.
Flags byte
// Probability
Probability float32
// Level现在的水平
Level int
}
func (c spanContext) isSampled() bool {
return (c.Flags & flagSampled) == flagSampled
}
func (c spanContext) isDebug() bool {
return (c.Flags & flagDebug) == flagDebug
}
// IsValid check spanContext valid
func (c spanContext) IsValid() bool {
return c.TraceId != 0 && c.SpanId != 0
}
// emptyContext emptyContext
var emptyContext = spanContext{}
// 将spanContext转换为String
// {TraceId}:{SpanId}:{ParentId}:{flags}:[extend...]
// TraceId: uint64 base16
// SpanId: uint64 base16
// ParentId: uint64 base16
// 标志:
// - :0 sampled flag
// - :1 debug flag
// extend:
// sample-rate: s-{base16(BigEndian(float32))}
func (c spanContext) String() string {
base := make([]string, 4)
base[0] = strconv.FormatUint(c.TraceId, 16)
base[1] = strconv.FormatUint(c.SpanId, 16)
base[2] = strconv.FormatUint(c.ParentId, 16)
base[3] = strconv.FormatUint(uint64(c.Flags), 16)
return strings.Join(base, ":")
}
// 从字符串解析spanContext
func contextFromString(value string) (spanContext, error) {
if value == "" {
return emptyContext, errEmptyTracerString
}
items := strings.Split(value, ":")
if len(items) < 4 {
return emptyContext, errInvalidTracerString
}
parseHexUint64 := func(hex []string) ([]uint64, error) {
ret := make([]uint64, len(hex))
var err error
for i, hex := range hex {
ret[i], err = strconv.ParseUint(hex, 16, 64)
if err != nil {
break
}
}
return ret, err
}
ret, err := parseHexUint64(items[0:4])
if err != nil {
return emptyContext, errInvalidTracerString
}
sc := spanContext{
TraceId: ret[0],
SpanId: ret[1],
ParentId: ret[2],
Flags: byte(ret[3]),
}
return sc, nil
}