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 15package trace 16 17import ( 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 31type tracer struct{} 32 33var _ Tracer = &tracer{} 34 35// Span represents a span of a trace. It has an associated SpanContext, and 36// stores data accumulated while the span is active. 37// 38// Ideally users should interact with Spans by calling the functions in this 39// package that take a Context parameter. 40type span struct { 41 // data contains information recorded about the span. 42 // 43 // It will be non-nil if we are exporting the span or recording events for it. 44 // Otherwise, data is nil, and the Span is simply a carrier for the 45 // SpanContext, so that the trace ID is propagated. 46 data *SpanData 47 mu sync.Mutex // protects the contents of *data (but not the pointer value.) 48 spanContext SpanContext 49 50 // lruAttributes are capped at configured limit. When the capacity is reached an oldest entry 51 // is removed to create room for a new entry. 52 lruAttributes *lruMap 53 54 // annotations are stored in FIFO queue capped by configured limit. 55 annotations *evictedQueue 56 57 // messageEvents are stored in FIFO queue capped by configured limit. 58 messageEvents *evictedQueue 59 60 // links are stored in FIFO queue capped by configured limit. 61 links *evictedQueue 62 63 // spanStore is the spanStore this span belongs to, if any, otherwise it is nil. 64 *spanStore 65 endOnce sync.Once 66 67 executionTracerTaskEnd func() // ends the execution tracer span 68} 69 70// IsRecordingEvents returns true if events are being recorded for this span. 71// Use this check to avoid computing expensive annotations when they will never 72// be used. 73func (s *span) IsRecordingEvents() bool { 74 if s == nil { 75 return false 76 } 77 return s.data != nil 78} 79 80// TraceOptions contains options associated with a trace span. 81type TraceOptions uint32 82 83// IsSampled returns true if the span will be exported. 84func (sc SpanContext) IsSampled() bool { 85 return sc.TraceOptions.IsSampled() 86} 87 88// setIsSampled sets the TraceOptions bit that determines whether the span will be exported. 89func (sc *SpanContext) setIsSampled(sampled bool) { 90 if sampled { 91 sc.TraceOptions |= 1 92 } else { 93 sc.TraceOptions &= ^TraceOptions(1) 94 } 95} 96 97// IsSampled returns true if the span will be exported. 98func (t TraceOptions) IsSampled() bool { 99 return t&1 == 1 100} 101 102// SpanContext contains the state that must propagate across process boundaries. 103// 104// SpanContext is not an implementation of context.Context. 105// TODO: add reference to external Census docs for SpanContext. 106type SpanContext struct { 107 TraceID TraceID 108 SpanID SpanID 109 TraceOptions TraceOptions 110 Tracestate *tracestate.Tracestate 111} 112 113type contextKey struct{} 114 115// FromContext returns the Span stored in a context, or nil if there isn't one. 116func (t *tracer) FromContext(ctx context.Context) *Span { 117 s, _ := ctx.Value(contextKey{}).(*Span) 118 return s 119} 120 121// NewContext returns a new context with the given Span attached. 122func (t *tracer) NewContext(parent context.Context, s *Span) context.Context { 123 return context.WithValue(parent, contextKey{}, s) 124} 125 126// All available span kinds. Span kind must be either one of these values. 127const ( 128 SpanKindUnspecified = iota 129 SpanKindServer 130 SpanKindClient 131) 132 133// StartOptions contains options concerning how a span is started. 134type StartOptions struct { 135 // Sampler to consult for this Span. If provided, it is always consulted. 136 // 137 // If not provided, then the behavior differs based on whether 138 // the parent of this Span is remote, local, or there is no parent. 139 // In the case of a remote parent or no parent, the 140 // default sampler (see Config) will be consulted. Otherwise, 141 // when there is a non-remote parent, no new sampling decision will be made: 142 // we will preserve the sampling of the parent. 143 Sampler Sampler 144 145 // SpanKind represents the kind of a span. If none is set, 146 // SpanKindUnspecified is used. 147 SpanKind int 148} 149 150// StartOption apply changes to StartOptions. 151type StartOption func(*StartOptions) 152 153// WithSpanKind makes new spans to be created with the given kind. 154func WithSpanKind(spanKind int) StartOption { 155 return func(o *StartOptions) { 156 o.SpanKind = spanKind 157 } 158} 159 160// WithSampler makes new spans to be be created with a custom sampler. 161// Otherwise, the global sampler is used. 162func WithSampler(sampler Sampler) StartOption { 163 return func(o *StartOptions) { 164 o.Sampler = sampler 165 } 166} 167 168// StartSpan starts a new child span of the current span in the context. If 169// there is no span in the context, creates a new trace and span. 170// 171// Returned context contains the newly created span. You can use it to 172// propagate the returned span in process. 173func (t *tracer) StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, *Span) { 174 var opts StartOptions 175 var parent SpanContext 176 if p := t.FromContext(ctx); p != nil { 177 if ps, ok := p.internal.(*span); ok { 178 ps.addChild() 179 } 180 parent = p.SpanContext() 181 } 182 for _, op := range o { 183 op(&opts) 184 } 185 span := startSpanInternal(name, parent != SpanContext{}, parent, false, opts) 186 187 ctx, end := startExecutionTracerTask(ctx, name) 188 span.executionTracerTaskEnd = end 189 extSpan := NewSpan(span) 190 return t.NewContext(ctx, extSpan), extSpan 191} 192 193// StartSpanWithRemoteParent starts a new child span of the span from the given parent. 194// 195// If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is 196// preferred for cases where the parent is propagated via an incoming request. 197// 198// Returned context contains the newly created span. You can use it to 199// propagate the returned span in process. 200func (t *tracer) StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, *Span) { 201 var opts StartOptions 202 for _, op := range o { 203 op(&opts) 204 } 205 span := startSpanInternal(name, parent != SpanContext{}, parent, true, opts) 206 ctx, end := startExecutionTracerTask(ctx, name) 207 span.executionTracerTaskEnd = end 208 extSpan := NewSpan(span) 209 return t.NewContext(ctx, extSpan), extSpan 210} 211 212func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *span { 213 s := &span{} 214 s.spanContext = parent 215 216 cfg := config.Load().(*Config) 217 if gen, ok := cfg.IDGenerator.(*defaultIDGenerator); ok { 218 // lazy initialization 219 gen.init() 220 } 221 222 if !hasParent { 223 s.spanContext.TraceID = cfg.IDGenerator.NewTraceID() 224 } 225 s.spanContext.SpanID = cfg.IDGenerator.NewSpanID() 226 sampler := cfg.DefaultSampler 227 228 if !hasParent || remoteParent || o.Sampler != nil { 229 // If this span is the child of a local span and no Sampler is set in the 230 // options, keep the parent's TraceOptions. 231 // 232 // Otherwise, consult the Sampler in the options if it is non-nil, otherwise 233 // the default sampler. 234 if o.Sampler != nil { 235 sampler = o.Sampler 236 } 237 s.spanContext.setIsSampled(sampler(SamplingParameters{ 238 ParentContext: parent, 239 TraceID: s.spanContext.TraceID, 240 SpanID: s.spanContext.SpanID, 241 Name: name, 242 HasRemoteParent: remoteParent}).Sample) 243 } 244 245 if !internal.LocalSpanStoreEnabled && !s.spanContext.IsSampled() { 246 return s 247 } 248 249 s.data = &SpanData{ 250 SpanContext: s.spanContext, 251 StartTime: time.Now(), 252 SpanKind: o.SpanKind, 253 Name: name, 254 HasRemoteParent: remoteParent, 255 } 256 s.lruAttributes = newLruMap(cfg.MaxAttributesPerSpan) 257 s.annotations = newEvictedQueue(cfg.MaxAnnotationEventsPerSpan) 258 s.messageEvents = newEvictedQueue(cfg.MaxMessageEventsPerSpan) 259 s.links = newEvictedQueue(cfg.MaxLinksPerSpan) 260 261 if hasParent { 262 s.data.ParentSpanID = parent.SpanID 263 } 264 if internal.LocalSpanStoreEnabled { 265 var ss *spanStore 266 ss = spanStoreForNameCreateIfNew(name) 267 if ss != nil { 268 s.spanStore = ss 269 ss.add(s) 270 } 271 } 272 273 return s 274} 275 276// End ends the span. 277func (s *span) End() { 278 if s == nil { 279 return 280 } 281 if s.executionTracerTaskEnd != nil { 282 s.executionTracerTaskEnd() 283 } 284 if !s.IsRecordingEvents() { 285 return 286 } 287 s.endOnce.Do(func() { 288 exp, _ := exporters.Load().(exportersMap) 289 mustExport := s.spanContext.IsSampled() && len(exp) > 0 290 if s.spanStore != nil || mustExport { 291 sd := s.makeSpanData() 292 sd.EndTime = internal.MonotonicEndTime(sd.StartTime) 293 if s.spanStore != nil { 294 s.spanStore.finished(s, sd) 295 } 296 if mustExport { 297 for e := range exp { 298 e.ExportSpan(sd) 299 } 300 } 301 } 302 }) 303} 304 305// makeSpanData produces a SpanData representing the current state of the Span. 306// It requires that s.data is non-nil. 307func (s *span) makeSpanData() *SpanData { 308 var sd SpanData 309 s.mu.Lock() 310 sd = *s.data 311 if s.lruAttributes.len() > 0 { 312 sd.Attributes = s.lruAttributesToAttributeMap() 313 sd.DroppedAttributeCount = s.lruAttributes.droppedCount 314 } 315 if len(s.annotations.queue) > 0 { 316 sd.Annotations = s.interfaceArrayToAnnotationArray() 317 sd.DroppedAnnotationCount = s.annotations.droppedCount 318 } 319 if len(s.messageEvents.queue) > 0 { 320 sd.MessageEvents = s.interfaceArrayToMessageEventArray() 321 sd.DroppedMessageEventCount = s.messageEvents.droppedCount 322 } 323 if len(s.links.queue) > 0 { 324 sd.Links = s.interfaceArrayToLinksArray() 325 sd.DroppedLinkCount = s.links.droppedCount 326 } 327 s.mu.Unlock() 328 return &sd 329} 330 331// SpanContext returns the SpanContext of the span. 332func (s *span) SpanContext() SpanContext { 333 if s == nil { 334 return SpanContext{} 335 } 336 return s.spanContext 337} 338 339// SetName sets the name of the span, if it is recording events. 340func (s *span) SetName(name string) { 341 if !s.IsRecordingEvents() { 342 return 343 } 344 s.mu.Lock() 345 s.data.Name = name 346 s.mu.Unlock() 347} 348 349// SetStatus sets the status of the span, if it is recording events. 350func (s *span) SetStatus(status Status) { 351 if !s.IsRecordingEvents() { 352 return 353 } 354 s.mu.Lock() 355 s.data.Status = status 356 s.mu.Unlock() 357} 358 359func (s *span) interfaceArrayToLinksArray() []Link { 360 linksArr := make([]Link, 0, len(s.links.queue)) 361 for _, value := range s.links.queue { 362 linksArr = append(linksArr, value.(Link)) 363 } 364 return linksArr 365} 366 367func (s *span) interfaceArrayToMessageEventArray() []MessageEvent { 368 messageEventArr := make([]MessageEvent, 0, len(s.messageEvents.queue)) 369 for _, value := range s.messageEvents.queue { 370 messageEventArr = append(messageEventArr, value.(MessageEvent)) 371 } 372 return messageEventArr 373} 374 375func (s *span) interfaceArrayToAnnotationArray() []Annotation { 376 annotationArr := make([]Annotation, 0, len(s.annotations.queue)) 377 for _, value := range s.annotations.queue { 378 annotationArr = append(annotationArr, value.(Annotation)) 379 } 380 return annotationArr 381} 382 383func (s *span) lruAttributesToAttributeMap() map[string]interface{} { 384 attributes := make(map[string]interface{}, s.lruAttributes.len()) 385 for _, key := range s.lruAttributes.keys() { 386 value, ok := s.lruAttributes.get(key) 387 if ok { 388 keyStr := key.(string) 389 attributes[keyStr] = value 390 } 391 } 392 return attributes 393} 394 395func (s *span) copyToCappedAttributes(attributes []Attribute) { 396 for _, a := range attributes { 397 s.lruAttributes.add(a.key, a.value) 398 } 399} 400 401func (s *span) addChild() { 402 if !s.IsRecordingEvents() { 403 return 404 } 405 s.mu.Lock() 406 s.data.ChildSpanCount++ 407 s.mu.Unlock() 408} 409 410// AddAttributes sets attributes in the span. 411// 412// Existing attributes whose keys appear in the attributes parameter are overwritten. 413func (s *span) AddAttributes(attributes ...Attribute) { 414 if !s.IsRecordingEvents() { 415 return 416 } 417 s.mu.Lock() 418 s.copyToCappedAttributes(attributes) 419 s.mu.Unlock() 420} 421 422func (s *span) printStringInternal(attributes []Attribute, str string) { 423 now := time.Now() 424 var am map[string]interface{} 425 if len(attributes) != 0 { 426 am = make(map[string]interface{}, len(attributes)) 427 for _, attr := range attributes { 428 am[attr.key] = attr.value 429 } 430 } 431 s.mu.Lock() 432 s.annotations.add(Annotation{ 433 Time: now, 434 Message: str, 435 Attributes: am, 436 }) 437 s.mu.Unlock() 438} 439 440// Annotate adds an annotation with attributes. 441// Attributes can be nil. 442func (s *span) Annotate(attributes []Attribute, str string) { 443 if !s.IsRecordingEvents() { 444 return 445 } 446 s.printStringInternal(attributes, str) 447} 448 449// Annotatef adds an annotation with attributes. 450func (s *span) Annotatef(attributes []Attribute, format string, a ...interface{}) { 451 if !s.IsRecordingEvents() { 452 return 453 } 454 s.printStringInternal(attributes, fmt.Sprintf(format, a...)) 455} 456 457// AddMessageSendEvent adds a message send event to the span. 458// 459// messageID is an identifier for the message, which is recommended to be 460// unique in this span and the same between the send event and the receive 461// event (this allows to identify a message between the sender and receiver). 462// For example, this could be a sequence id. 463func (s *span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64) { 464 if !s.IsRecordingEvents() { 465 return 466 } 467 now := time.Now() 468 s.mu.Lock() 469 s.messageEvents.add(MessageEvent{ 470 Time: now, 471 EventType: MessageEventTypeSent, 472 MessageID: messageID, 473 UncompressedByteSize: uncompressedByteSize, 474 CompressedByteSize: compressedByteSize, 475 }) 476 s.mu.Unlock() 477} 478 479// AddMessageReceiveEvent adds a message receive event to the span. 480// 481// messageID is an identifier for the message, which is recommended to be 482// unique in this span and the same between the send event and the receive 483// event (this allows to identify a message between the sender and receiver). 484// For example, this could be a sequence id. 485func (s *span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64) { 486 if !s.IsRecordingEvents() { 487 return 488 } 489 now := time.Now() 490 s.mu.Lock() 491 s.messageEvents.add(MessageEvent{ 492 Time: now, 493 EventType: MessageEventTypeRecv, 494 MessageID: messageID, 495 UncompressedByteSize: uncompressedByteSize, 496 CompressedByteSize: compressedByteSize, 497 }) 498 s.mu.Unlock() 499} 500 501// AddLink adds a link to the span. 502func (s *span) AddLink(l Link) { 503 if !s.IsRecordingEvents() { 504 return 505 } 506 s.mu.Lock() 507 s.links.add(l) 508 s.mu.Unlock() 509} 510 511func (s *span) String() string { 512 if s == nil { 513 return "<nil>" 514 } 515 if s.data == nil { 516 return fmt.Sprintf("span %s", s.spanContext.SpanID) 517 } 518 s.mu.Lock() 519 str := fmt.Sprintf("span %s %q", s.spanContext.SpanID, s.data.Name) 520 s.mu.Unlock() 521 return str 522} 523 524var config atomic.Value // access atomically 525 526func init() { 527 config.Store(&Config{ 528 DefaultSampler: ProbabilitySampler(defaultSamplingProbability), 529 IDGenerator: &defaultIDGenerator{}, 530 MaxAttributesPerSpan: DefaultMaxAttributesPerSpan, 531 MaxAnnotationEventsPerSpan: DefaultMaxAnnotationEventsPerSpan, 532 MaxMessageEventsPerSpan: DefaultMaxMessageEventsPerSpan, 533 MaxLinksPerSpan: DefaultMaxLinksPerSpan, 534 }) 535} 536 537type defaultIDGenerator struct { 538 sync.Mutex 539 540 // Please keep these as the first fields 541 // so that these 8 byte fields will be aligned on addresses 542 // divisible by 8, on both 32-bit and 64-bit machines when 543 // performing atomic increments and accesses. 544 // See: 545 // * https://github.com/census-instrumentation/opencensus-go/issues/587 546 // * https://github.com/census-instrumentation/opencensus-go/issues/865 547 // * https://golang.org/pkg/sync/atomic/#pkg-note-BUG 548 nextSpanID uint64 549 spanIDInc uint64 550 551 traceIDAdd [2]uint64 552 traceIDRand *rand.Rand 553 554 initOnce sync.Once 555} 556 557// init initializes the generator on the first call to avoid consuming entropy 558// unnecessarily. 559func (gen *defaultIDGenerator) init() { 560 gen.initOnce.Do(func() { 561 // initialize traceID and spanID generators. 562 var rngSeed int64 563 for _, p := range []interface{}{ 564 &rngSeed, &gen.traceIDAdd, &gen.nextSpanID, &gen.spanIDInc, 565 } { 566 binary.Read(crand.Reader, binary.LittleEndian, p) 567 } 568 gen.traceIDRand = rand.New(rand.NewSource(rngSeed)) 569 gen.spanIDInc |= 1 570 }) 571} 572 573// NewSpanID returns a non-zero span ID from a randomly-chosen sequence. 574func (gen *defaultIDGenerator) NewSpanID() [8]byte { 575 var id uint64 576 for id == 0 { 577 id = atomic.AddUint64(&gen.nextSpanID, gen.spanIDInc) 578 } 579 var sid [8]byte 580 binary.LittleEndian.PutUint64(sid[:], id) 581 return sid 582} 583 584// NewTraceID returns a non-zero trace ID from a randomly-chosen sequence. 585// mu should be held while this function is called. 586func (gen *defaultIDGenerator) NewTraceID() [16]byte { 587 var tid [16]byte 588 // Construct the trace ID from two outputs of traceIDRand, with a constant 589 // added to each half for additional entropy. 590 gen.Lock() 591 binary.LittleEndian.PutUint64(tid[0:8], gen.traceIDRand.Uint64()+gen.traceIDAdd[0]) 592 binary.LittleEndian.PutUint64(tid[8:16], gen.traceIDRand.Uint64()+gen.traceIDAdd[1]) 593 gen.Unlock() 594 return tid 595} 596