diff options
Diffstat (limited to 'vendor/go.opencensus.io/trace/trace.go')
-rw-r--r-- | vendor/go.opencensus.io/trace/trace.go | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/vendor/go.opencensus.io/trace/trace.go b/vendor/go.opencensus.io/trace/trace.go new file mode 100644 index 0000000..9e5e5f0 --- /dev/null +++ b/vendor/go.opencensus.io/trace/trace.go | |||
@@ -0,0 +1,516 @@ | |||
1 | // Copyright 2017, OpenCensus Authors | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | // you may not use this file except in compliance with the License. | ||
5 | // You may obtain a copy of the License at | ||
6 | // | ||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | // | ||
9 | // Unless required by applicable law or agreed to in writing, software | ||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | // See the License for the specific language governing permissions and | ||
13 | // limitations under the License. | ||
14 | |||
15 | package trace | ||
16 | |||
17 | import ( | ||
18 | "context" | ||
19 | crand "crypto/rand" | ||
20 | "encoding/binary" | ||
21 | "fmt" | ||
22 | "math/rand" | ||
23 | "sync" | ||
24 | "sync/atomic" | ||
25 | "time" | ||
26 | |||
27 | "go.opencensus.io/internal" | ||
28 | "go.opencensus.io/trace/tracestate" | ||
29 | ) | ||
30 | |||
31 | // Span represents a span of a trace. It has an associated SpanContext, and | ||
32 | // stores data accumulated while the span is active. | ||
33 | // | ||
34 | // Ideally users should interact with Spans by calling the functions in this | ||
35 | // package that take a Context parameter. | ||
36 | type Span struct { | ||
37 | // data contains information recorded about the span. | ||
38 | // | ||
39 | // It will be non-nil if we are exporting the span or recording events for it. | ||
40 | // Otherwise, data is nil, and the Span is simply a carrier for the | ||
41 | // SpanContext, so that the trace ID is propagated. | ||
42 | data *SpanData | ||
43 | mu sync.Mutex // protects the contents of *data (but not the pointer value.) | ||
44 | spanContext SpanContext | ||
45 | // spanStore is the spanStore this span belongs to, if any, otherwise it is nil. | ||
46 | *spanStore | ||
47 | endOnce sync.Once | ||
48 | |||
49 | executionTracerTaskEnd func() // ends the execution tracer span | ||
50 | } | ||
51 | |||
52 | // IsRecordingEvents returns true if events are being recorded for this span. | ||
53 | // Use this check to avoid computing expensive annotations when they will never | ||
54 | // be used. | ||
55 | func (s *Span) IsRecordingEvents() bool { | ||
56 | if s == nil { | ||
57 | return false | ||
58 | } | ||
59 | return s.data != nil | ||
60 | } | ||
61 | |||
62 | // TraceOptions contains options associated with a trace span. | ||
63 | type TraceOptions uint32 | ||
64 | |||
65 | // IsSampled returns true if the span will be exported. | ||
66 | func (sc SpanContext) IsSampled() bool { | ||
67 | return sc.TraceOptions.IsSampled() | ||
68 | } | ||
69 | |||
70 | // setIsSampled sets the TraceOptions bit that determines whether the span will be exported. | ||
71 | func (sc *SpanContext) setIsSampled(sampled bool) { | ||
72 | if sampled { | ||
73 | sc.TraceOptions |= 1 | ||
74 | } else { | ||
75 | sc.TraceOptions &= ^TraceOptions(1) | ||
76 | } | ||
77 | } | ||
78 | |||
79 | // IsSampled returns true if the span will be exported. | ||
80 | func (t TraceOptions) IsSampled() bool { | ||
81 | return t&1 == 1 | ||
82 | } | ||
83 | |||
84 | // SpanContext contains the state that must propagate across process boundaries. | ||
85 | // | ||
86 | // SpanContext is not an implementation of context.Context. | ||
87 | // TODO: add reference to external Census docs for SpanContext. | ||
88 | type SpanContext struct { | ||
89 | TraceID TraceID | ||
90 | SpanID SpanID | ||
91 | TraceOptions TraceOptions | ||
92 | Tracestate *tracestate.Tracestate | ||
93 | } | ||
94 | |||
95 | type contextKey struct{} | ||
96 | |||
97 | // FromContext returns the Span stored in a context, or nil if there isn't one. | ||
98 | func FromContext(ctx context.Context) *Span { | ||
99 | s, _ := ctx.Value(contextKey{}).(*Span) | ||
100 | return s | ||
101 | } | ||
102 | |||
103 | // NewContext returns a new context with the given Span attached. | ||
104 | func NewContext(parent context.Context, s *Span) context.Context { | ||
105 | return context.WithValue(parent, contextKey{}, s) | ||
106 | } | ||
107 | |||
108 | // All available span kinds. Span kind must be either one of these values. | ||
109 | const ( | ||
110 | SpanKindUnspecified = iota | ||
111 | SpanKindServer | ||
112 | SpanKindClient | ||
113 | ) | ||
114 | |||
115 | // StartOptions contains options concerning how a span is started. | ||
116 | type StartOptions struct { | ||
117 | // Sampler to consult for this Span. If provided, it is always consulted. | ||
118 | // | ||
119 | // If not provided, then the behavior differs based on whether | ||
120 | // the parent of this Span is remote, local, or there is no parent. | ||
121 | // In the case of a remote parent or no parent, the | ||
122 | // default sampler (see Config) will be consulted. Otherwise, | ||
123 | // when there is a non-remote parent, no new sampling decision will be made: | ||
124 | // we will preserve the sampling of the parent. | ||
125 | Sampler Sampler | ||
126 | |||
127 | // SpanKind represents the kind of a span. If none is set, | ||
128 | // SpanKindUnspecified is used. | ||
129 | SpanKind int | ||
130 | } | ||
131 | |||
132 | // StartOption apply changes to StartOptions. | ||
133 | type StartOption func(*StartOptions) | ||
134 | |||
135 | // WithSpanKind makes new spans to be created with the given kind. | ||
136 | func WithSpanKind(spanKind int) StartOption { | ||
137 | return func(o *StartOptions) { | ||
138 | o.SpanKind = spanKind | ||
139 | } | ||
140 | } | ||
141 | |||
142 | // WithSampler makes new spans to be be created with a custom sampler. | ||
143 | // Otherwise, the global sampler is used. | ||
144 | func WithSampler(sampler Sampler) StartOption { | ||
145 | return func(o *StartOptions) { | ||
146 | o.Sampler = sampler | ||
147 | } | ||
148 | } | ||
149 | |||
150 | // StartSpan starts a new child span of the current span in the context. If | ||
151 | // there is no span in the context, creates a new trace and span. | ||
152 | // | ||
153 | // Returned context contains the newly created span. You can use it to | ||
154 | // propagate the returned span in process. | ||
155 | func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, *Span) { | ||
156 | var opts StartOptions | ||
157 | var parent SpanContext | ||
158 | if p := FromContext(ctx); p != nil { | ||
159 | parent = p.spanContext | ||
160 | } | ||
161 | for _, op := range o { | ||
162 | op(&opts) | ||
163 | } | ||
164 | span := startSpanInternal(name, parent != SpanContext{}, parent, false, opts) | ||
165 | |||
166 | ctx, end := startExecutionTracerTask(ctx, name) | ||
167 | span.executionTracerTaskEnd = end | ||
168 | return NewContext(ctx, span), span | ||
169 | } | ||
170 | |||
171 | // StartSpanWithRemoteParent starts a new child span of the span from the given parent. | ||
172 | // | ||
173 | // If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is | ||
174 | // preferred for cases where the parent is propagated via an incoming request. | ||
175 | // | ||
176 | // Returned context contains the newly created span. You can use it to | ||
177 | // propagate the returned span in process. | ||
178 | func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, *Span) { | ||
179 | var opts StartOptions | ||
180 | for _, op := range o { | ||
181 | op(&opts) | ||
182 | } | ||
183 | span := startSpanInternal(name, parent != SpanContext{}, parent, true, opts) | ||
184 | ctx, end := startExecutionTracerTask(ctx, name) | ||
185 | span.executionTracerTaskEnd = end | ||
186 | return NewContext(ctx, span), span | ||
187 | } | ||
188 | |||
189 | func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *Span { | ||
190 | span := &Span{} | ||
191 | span.spanContext = parent | ||
192 | |||
193 | cfg := config.Load().(*Config) | ||
194 | |||
195 | if !hasParent { | ||
196 | span.spanContext.TraceID = cfg.IDGenerator.NewTraceID() | ||
197 | } | ||
198 | span.spanContext.SpanID = cfg.IDGenerator.NewSpanID() | ||
199 | sampler := cfg.DefaultSampler | ||
200 | |||
201 | if !hasParent || remoteParent || o.Sampler != nil { | ||
202 | // If this span is the child of a local span and no Sampler is set in the | ||
203 | // options, keep the parent's TraceOptions. | ||
204 | // | ||
205 | // Otherwise, consult the Sampler in the options if it is non-nil, otherwise | ||
206 | // the default sampler. | ||
207 | if o.Sampler != nil { | ||
208 | sampler = o.Sampler | ||
209 | } | ||
210 | span.spanContext.setIsSampled(sampler(SamplingParameters{ | ||
211 | ParentContext: parent, | ||
212 | TraceID: span.spanContext.TraceID, | ||
213 | SpanID: span.spanContext.SpanID, | ||
214 | Name: name, | ||
215 | HasRemoteParent: remoteParent}).Sample) | ||
216 | } | ||
217 | |||
218 | if !internal.LocalSpanStoreEnabled && !span.spanContext.IsSampled() { | ||
219 | return span | ||
220 | } | ||
221 | |||
222 | span.data = &SpanData{ | ||
223 | SpanContext: span.spanContext, | ||
224 | StartTime: time.Now(), | ||
225 | SpanKind: o.SpanKind, | ||
226 | Name: name, | ||
227 | HasRemoteParent: remoteParent, | ||
228 | } | ||
229 | if hasParent { | ||
230 | span.data.ParentSpanID = parent.SpanID | ||
231 | } | ||
232 | if internal.LocalSpanStoreEnabled { | ||
233 | var ss *spanStore | ||
234 | ss = spanStoreForNameCreateIfNew(name) | ||
235 | if ss != nil { | ||
236 | span.spanStore = ss | ||
237 | ss.add(span) | ||
238 | } | ||
239 | } | ||
240 | |||
241 | return span | ||
242 | } | ||
243 | |||
244 | // End ends the span. | ||
245 | func (s *Span) End() { | ||
246 | if s == nil { | ||
247 | return | ||
248 | } | ||
249 | if s.executionTracerTaskEnd != nil { | ||
250 | s.executionTracerTaskEnd() | ||
251 | } | ||
252 | if !s.IsRecordingEvents() { | ||
253 | return | ||
254 | } | ||
255 | s.endOnce.Do(func() { | ||
256 | exp, _ := exporters.Load().(exportersMap) | ||
257 | mustExport := s.spanContext.IsSampled() && len(exp) > 0 | ||
258 | if s.spanStore != nil || mustExport { | ||
259 | sd := s.makeSpanData() | ||
260 | sd.EndTime = internal.MonotonicEndTime(sd.StartTime) | ||
261 | if s.spanStore != nil { | ||
262 | s.spanStore.finished(s, sd) | ||
263 | } | ||
264 | if mustExport { | ||
265 | for e := range exp { | ||
266 | e.ExportSpan(sd) | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | }) | ||
271 | } | ||
272 | |||
273 | // makeSpanData produces a SpanData representing the current state of the Span. | ||
274 | // It requires that s.data is non-nil. | ||
275 | func (s *Span) makeSpanData() *SpanData { | ||
276 | var sd SpanData | ||
277 | s.mu.Lock() | ||
278 | sd = *s.data | ||
279 | if s.data.Attributes != nil { | ||
280 | sd.Attributes = make(map[string]interface{}) | ||
281 | for k, v := range s.data.Attributes { | ||
282 | sd.Attributes[k] = v | ||
283 | } | ||
284 | } | ||
285 | s.mu.Unlock() | ||
286 | return &sd | ||
287 | } | ||
288 | |||
289 | // SpanContext returns the SpanContext of the span. | ||
290 | func (s *Span) SpanContext() SpanContext { | ||
291 | if s == nil { | ||
292 | return SpanContext{} | ||
293 | } | ||
294 | return s.spanContext | ||
295 | } | ||
296 | |||
297 | // SetName sets the name of the span, if it is recording events. | ||
298 | func (s *Span) SetName(name string) { | ||
299 | if !s.IsRecordingEvents() { | ||
300 | return | ||
301 | } | ||
302 | s.mu.Lock() | ||
303 | s.data.Name = name | ||
304 | s.mu.Unlock() | ||
305 | } | ||
306 | |||
307 | // SetStatus sets the status of the span, if it is recording events. | ||
308 | func (s *Span) SetStatus(status Status) { | ||
309 | if !s.IsRecordingEvents() { | ||
310 | return | ||
311 | } | ||
312 | s.mu.Lock() | ||
313 | s.data.Status = status | ||
314 | s.mu.Unlock() | ||
315 | } | ||
316 | |||
317 | // AddAttributes sets attributes in the span. | ||
318 | // | ||
319 | // Existing attributes whose keys appear in the attributes parameter are overwritten. | ||
320 | func (s *Span) AddAttributes(attributes ...Attribute) { | ||
321 | if !s.IsRecordingEvents() { | ||
322 | return | ||
323 | } | ||
324 | s.mu.Lock() | ||
325 | if s.data.Attributes == nil { | ||
326 | s.data.Attributes = make(map[string]interface{}) | ||
327 | } | ||
328 | copyAttributes(s.data.Attributes, attributes) | ||
329 | s.mu.Unlock() | ||
330 | } | ||
331 | |||
332 | // copyAttributes copies a slice of Attributes into a map. | ||
333 | func copyAttributes(m map[string]interface{}, attributes []Attribute) { | ||
334 | for _, a := range attributes { | ||
335 | m[a.key] = a.value | ||
336 | } | ||
337 | } | ||
338 | |||
339 | func (s *Span) lazyPrintfInternal(attributes []Attribute, format string, a ...interface{}) { | ||
340 | now := time.Now() | ||
341 | msg := fmt.Sprintf(format, a...) | ||
342 | var m map[string]interface{} | ||
343 | s.mu.Lock() | ||
344 | if len(attributes) != 0 { | ||
345 | m = make(map[string]interface{}) | ||
346 | copyAttributes(m, attributes) | ||
347 | } | ||
348 | s.data.Annotations = append(s.data.Annotations, Annotation{ | ||
349 | Time: now, | ||
350 | Message: msg, | ||
351 | Attributes: m, | ||
352 | }) | ||
353 | s.mu.Unlock() | ||
354 | } | ||
355 | |||
356 | func (s *Span) printStringInternal(attributes []Attribute, str string) { | ||
357 | now := time.Now() | ||
358 | var a map[string]interface{} | ||
359 | s.mu.Lock() | ||
360 | if len(attributes) != 0 { | ||
361 | a = make(map[string]interface{}) | ||
362 | copyAttributes(a, attributes) | ||
363 | } | ||
364 | s.data.Annotations = append(s.data.Annotations, Annotation{ | ||
365 | Time: now, | ||
366 | Message: str, | ||
367 | Attributes: a, | ||
368 | }) | ||
369 | s.mu.Unlock() | ||
370 | } | ||
371 | |||
372 | // Annotate adds an annotation with attributes. | ||
373 | // Attributes can be nil. | ||
374 | func (s *Span) Annotate(attributes []Attribute, str string) { | ||
375 | if !s.IsRecordingEvents() { | ||
376 | return | ||
377 | } | ||
378 | s.printStringInternal(attributes, str) | ||
379 | } | ||
380 | |||
381 | // Annotatef adds an annotation with attributes. | ||
382 | func (s *Span) Annotatef(attributes []Attribute, format string, a ...interface{}) { | ||
383 | if !s.IsRecordingEvents() { | ||
384 | return | ||
385 | } | ||
386 | s.lazyPrintfInternal(attributes, format, a...) | ||
387 | } | ||
388 | |||
389 | // AddMessageSendEvent adds a message send event to the span. | ||
390 | // | ||
391 | // messageID is an identifier for the message, which is recommended to be | ||
392 | // unique in this span and the same between the send event and the receive | ||
393 | // event (this allows to identify a message between the sender and receiver). | ||
394 | // For example, this could be a sequence id. | ||
395 | func (s *Span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64) { | ||
396 | if !s.IsRecordingEvents() { | ||
397 | return | ||
398 | } | ||
399 | now := time.Now() | ||
400 | s.mu.Lock() | ||
401 | s.data.MessageEvents = append(s.data.MessageEvents, MessageEvent{ | ||
402 | Time: now, | ||
403 | EventType: MessageEventTypeSent, | ||
404 | MessageID: messageID, | ||
405 | UncompressedByteSize: uncompressedByteSize, | ||
406 | CompressedByteSize: compressedByteSize, | ||
407 | }) | ||
408 | s.mu.Unlock() | ||
409 | } | ||
410 | |||
411 | // AddMessageReceiveEvent adds a message receive event to the span. | ||
412 | // | ||
413 | // messageID is an identifier for the message, which is recommended to be | ||
414 | // unique in this span and the same between the send event and the receive | ||
415 | // event (this allows to identify a message between the sender and receiver). | ||
416 | // For example, this could be a sequence id. | ||
417 | func (s *Span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64) { | ||
418 | if !s.IsRecordingEvents() { | ||
419 | return | ||
420 | } | ||
421 | now := time.Now() | ||
422 | s.mu.Lock() | ||
423 | s.data.MessageEvents = append(s.data.MessageEvents, MessageEvent{ | ||
424 | Time: now, | ||
425 | EventType: MessageEventTypeRecv, | ||
426 | MessageID: messageID, | ||
427 | UncompressedByteSize: uncompressedByteSize, | ||
428 | CompressedByteSize: compressedByteSize, | ||
429 | }) | ||
430 | s.mu.Unlock() | ||
431 | } | ||
432 | |||
433 | // AddLink adds a link to the span. | ||
434 | func (s *Span) AddLink(l Link) { | ||
435 | if !s.IsRecordingEvents() { | ||
436 | return | ||
437 | } | ||
438 | s.mu.Lock() | ||
439 | s.data.Links = append(s.data.Links, l) | ||
440 | s.mu.Unlock() | ||
441 | } | ||
442 | |||
443 | func (s *Span) String() string { | ||
444 | if s == nil { | ||
445 | return "<nil>" | ||
446 | } | ||
447 | if s.data == nil { | ||
448 | return fmt.Sprintf("span %s", s.spanContext.SpanID) | ||
449 | } | ||
450 | s.mu.Lock() | ||
451 | str := fmt.Sprintf("span %s %q", s.spanContext.SpanID, s.data.Name) | ||
452 | s.mu.Unlock() | ||
453 | return str | ||
454 | } | ||
455 | |||
456 | var config atomic.Value // access atomically | ||
457 | |||
458 | func init() { | ||
459 | gen := &defaultIDGenerator{} | ||
460 | // initialize traceID and spanID generators. | ||
461 | var rngSeed int64 | ||
462 | for _, p := range []interface{}{ | ||
463 | &rngSeed, &gen.traceIDAdd, &gen.nextSpanID, &gen.spanIDInc, | ||
464 | } { | ||
465 | binary.Read(crand.Reader, binary.LittleEndian, p) | ||
466 | } | ||
467 | gen.traceIDRand = rand.New(rand.NewSource(rngSeed)) | ||
468 | gen.spanIDInc |= 1 | ||
469 | |||
470 | config.Store(&Config{ | ||
471 | DefaultSampler: ProbabilitySampler(defaultSamplingProbability), | ||
472 | IDGenerator: gen, | ||
473 | }) | ||
474 | } | ||
475 | |||
476 | type defaultIDGenerator struct { | ||
477 | sync.Mutex | ||
478 | |||
479 | // Please keep these as the first fields | ||
480 | // so that these 8 byte fields will be aligned on addresses | ||
481 | // divisible by 8, on both 32-bit and 64-bit machines when | ||
482 | // performing atomic increments and accesses. | ||
483 | // See: | ||
484 | // * https://github.com/census-instrumentation/opencensus-go/issues/587 | ||
485 | // * https://github.com/census-instrumentation/opencensus-go/issues/865 | ||
486 | // * https://golang.org/pkg/sync/atomic/#pkg-note-BUG | ||
487 | nextSpanID uint64 | ||
488 | spanIDInc uint64 | ||
489 | |||
490 | traceIDAdd [2]uint64 | ||
491 | traceIDRand *rand.Rand | ||
492 | } | ||
493 | |||
494 | // NewSpanID returns a non-zero span ID from a randomly-chosen sequence. | ||
495 | func (gen *defaultIDGenerator) NewSpanID() [8]byte { | ||
496 | var id uint64 | ||
497 | for id == 0 { | ||
498 | id = atomic.AddUint64(&gen.nextSpanID, gen.spanIDInc) | ||
499 | } | ||
500 | var sid [8]byte | ||
501 | binary.LittleEndian.PutUint64(sid[:], id) | ||
502 | return sid | ||
503 | } | ||
504 | |||
505 | // NewTraceID returns a non-zero trace ID from a randomly-chosen sequence. | ||
506 | // mu should be held while this function is called. | ||
507 | func (gen *defaultIDGenerator) NewTraceID() [16]byte { | ||
508 | var tid [16]byte | ||
509 | // Construct the trace ID from two outputs of traceIDRand, with a constant | ||
510 | // added to each half for additional entropy. | ||
511 | gen.Lock() | ||
512 | binary.LittleEndian.PutUint64(tid[0:8], gen.traceIDRand.Uint64()+gen.traceIDAdd[0]) | ||
513 | binary.LittleEndian.PutUint64(tid[8:16], gen.traceIDRand.Uint64()+gen.traceIDAdd[1]) | ||
514 | gen.Unlock() | ||
515 | return tid | ||
516 | } | ||