1 // Copyright 2017, OpenCensus Authors
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
27 "go.opencensus.io/internal"
28 "go.opencensus.io/trace/tracestate"
31 // Span represents a span of a trace. It has an associated SpanContext, and
32 // stores data accumulated while the span is active.
34 // Ideally users should interact with Spans by calling the functions in this
35 // package that take a Context parameter.
37 // data contains information recorded about the span.
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.
43 mu sync.Mutex // protects the contents of *data (but not the pointer value.)
44 spanContext SpanContext
46 // lruAttributes are capped at configured limit. When the capacity is reached an oldest entry
47 // is removed to create room for a new entry.
50 // annotations are stored in FIFO queue capped by configured limit.
51 annotations *evictedQueue
53 // messageEvents are stored in FIFO queue capped by configured limit.
54 messageEvents *evictedQueue
56 // links are stored in FIFO queue capped by configured limit.
59 // spanStore is the spanStore this span belongs to, if any, otherwise it is nil.
63 executionTracerTaskEnd func() // ends the execution tracer span
66 // IsRecordingEvents returns true if events are being recorded for this span.
67 // Use this check to avoid computing expensive annotations when they will never
69 func (s *Span) IsRecordingEvents() bool {
76 // TraceOptions contains options associated with a trace span.
77 type TraceOptions uint32
79 // IsSampled returns true if the span will be exported.
80 func (sc SpanContext) IsSampled() bool {
81 return sc.TraceOptions.IsSampled()
84 // setIsSampled sets the TraceOptions bit that determines whether the span will be exported.
85 func (sc *SpanContext) setIsSampled(sampled bool) {
89 sc.TraceOptions &= ^TraceOptions(1)
93 // IsSampled returns true if the span will be exported.
94 func (t TraceOptions) IsSampled() bool {
98 // SpanContext contains the state that must propagate across process boundaries.
100 // SpanContext is not an implementation of context.Context.
101 // TODO: add reference to external Census docs for SpanContext.
102 type SpanContext struct {
105 TraceOptions TraceOptions
106 Tracestate *tracestate.Tracestate
109 type contextKey struct{}
111 // FromContext returns the Span stored in a context, or nil if there isn't one.
112 func FromContext(ctx context.Context) *Span {
113 s, _ := ctx.Value(contextKey{}).(*Span)
117 // NewContext returns a new context with the given Span attached.
118 func NewContext(parent context.Context, s *Span) context.Context {
119 return context.WithValue(parent, contextKey{}, s)
122 // All available span kinds. Span kind must be either one of these values.
124 SpanKindUnspecified = iota
129 // StartOptions contains options concerning how a span is started.
130 type StartOptions struct {
131 // Sampler to consult for this Span. If provided, it is always consulted.
133 // If not provided, then the behavior differs based on whether
134 // the parent of this Span is remote, local, or there is no parent.
135 // In the case of a remote parent or no parent, the
136 // default sampler (see Config) will be consulted. Otherwise,
137 // when there is a non-remote parent, no new sampling decision will be made:
138 // we will preserve the sampling of the parent.
141 // SpanKind represents the kind of a span. If none is set,
142 // SpanKindUnspecified is used.
146 // StartOption apply changes to StartOptions.
147 type StartOption func(*StartOptions)
149 // WithSpanKind makes new spans to be created with the given kind.
150 func WithSpanKind(spanKind int) StartOption {
151 return func(o *StartOptions) {
152 o.SpanKind = spanKind
156 // WithSampler makes new spans to be be created with a custom sampler.
157 // Otherwise, the global sampler is used.
158 func WithSampler(sampler Sampler) StartOption {
159 return func(o *StartOptions) {
164 // StartSpan starts a new child span of the current span in the context. If
165 // there is no span in the context, creates a new trace and span.
167 // Returned context contains the newly created span. You can use it to
168 // propagate the returned span in process.
169 func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, *Span) {
170 var opts StartOptions
171 var parent SpanContext
172 if p := FromContext(ctx); p != nil {
174 parent = p.spanContext
176 for _, op := range o {
179 span := startSpanInternal(name, parent != SpanContext{}, parent, false, opts)
181 ctx, end := startExecutionTracerTask(ctx, name)
182 span.executionTracerTaskEnd = end
183 return NewContext(ctx, span), span
186 // StartSpanWithRemoteParent starts a new child span of the span from the given parent.
188 // If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is
189 // preferred for cases where the parent is propagated via an incoming request.
191 // Returned context contains the newly created span. You can use it to
192 // propagate the returned span in process.
193 func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, *Span) {
194 var opts StartOptions
195 for _, op := range o {
198 span := startSpanInternal(name, parent != SpanContext{}, parent, true, opts)
199 ctx, end := startExecutionTracerTask(ctx, name)
200 span.executionTracerTaskEnd = end
201 return NewContext(ctx, span), span
204 func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *Span {
206 span.spanContext = parent
208 cfg := config.Load().(*Config)
211 span.spanContext.TraceID = cfg.IDGenerator.NewTraceID()
213 span.spanContext.SpanID = cfg.IDGenerator.NewSpanID()
214 sampler := cfg.DefaultSampler
216 if !hasParent || remoteParent || o.Sampler != nil {
217 // If this span is the child of a local span and no Sampler is set in the
218 // options, keep the parent's TraceOptions.
220 // Otherwise, consult the Sampler in the options if it is non-nil, otherwise
221 // the default sampler.
222 if o.Sampler != nil {
225 span.spanContext.setIsSampled(sampler(SamplingParameters{
226 ParentContext: parent,
227 TraceID: span.spanContext.TraceID,
228 SpanID: span.spanContext.SpanID,
230 HasRemoteParent: remoteParent}).Sample)
233 if !internal.LocalSpanStoreEnabled && !span.spanContext.IsSampled() {
237 span.data = &SpanData{
238 SpanContext: span.spanContext,
239 StartTime: time.Now(),
240 SpanKind: o.SpanKind,
242 HasRemoteParent: remoteParent,
244 span.lruAttributes = newLruMap(cfg.MaxAttributesPerSpan)
245 span.annotations = newEvictedQueue(cfg.MaxAnnotationEventsPerSpan)
246 span.messageEvents = newEvictedQueue(cfg.MaxMessageEventsPerSpan)
247 span.links = newEvictedQueue(cfg.MaxLinksPerSpan)
250 span.data.ParentSpanID = parent.SpanID
252 if internal.LocalSpanStoreEnabled {
254 ss = spanStoreForNameCreateIfNew(name)
264 // End ends the span.
265 func (s *Span) End() {
269 if s.executionTracerTaskEnd != nil {
270 s.executionTracerTaskEnd()
272 if !s.IsRecordingEvents() {
275 s.endOnce.Do(func() {
276 exp, _ := exporters.Load().(exportersMap)
277 mustExport := s.spanContext.IsSampled() && len(exp) > 0
278 if s.spanStore != nil || mustExport {
279 sd := s.makeSpanData()
280 sd.EndTime = internal.MonotonicEndTime(sd.StartTime)
281 if s.spanStore != nil {
282 s.spanStore.finished(s, sd)
293 // makeSpanData produces a SpanData representing the current state of the Span.
294 // It requires that s.data is non-nil.
295 func (s *Span) makeSpanData() *SpanData {
299 if s.lruAttributes.simpleLruMap.Len() > 0 {
300 sd.Attributes = s.lruAttributesToAttributeMap()
301 sd.DroppedAttributeCount = s.lruAttributes.droppedCount
303 if len(s.annotations.queue) > 0 {
304 sd.Annotations = s.interfaceArrayToAnnotationArray()
305 sd.DroppedAnnotationCount = s.annotations.droppedCount
307 if len(s.messageEvents.queue) > 0 {
308 sd.MessageEvents = s.interfaceArrayToMessageEventArray()
309 sd.DroppedMessageEventCount = s.messageEvents.droppedCount
311 if len(s.links.queue) > 0 {
312 sd.Links = s.interfaceArrayToLinksArray()
313 sd.DroppedLinkCount = s.links.droppedCount
319 // SpanContext returns the SpanContext of the span.
320 func (s *Span) SpanContext() SpanContext {
327 // SetName sets the name of the span, if it is recording events.
328 func (s *Span) SetName(name string) {
329 if !s.IsRecordingEvents() {
337 // SetStatus sets the status of the span, if it is recording events.
338 func (s *Span) SetStatus(status Status) {
339 if !s.IsRecordingEvents() {
343 s.data.Status = status
347 func (s *Span) interfaceArrayToLinksArray() []Link {
348 linksArr := make([]Link, 0)
349 for _, value := range s.links.queue {
350 linksArr = append(linksArr, value.(Link))
355 func (s *Span) interfaceArrayToMessageEventArray() []MessageEvent {
356 messageEventArr := make([]MessageEvent, 0)
357 for _, value := range s.messageEvents.queue {
358 messageEventArr = append(messageEventArr, value.(MessageEvent))
360 return messageEventArr
363 func (s *Span) interfaceArrayToAnnotationArray() []Annotation {
364 annotationArr := make([]Annotation, 0)
365 for _, value := range s.annotations.queue {
366 annotationArr = append(annotationArr, value.(Annotation))
371 func (s *Span) lruAttributesToAttributeMap() map[string]interface{} {
372 attributes := make(map[string]interface{})
373 for _, key := range s.lruAttributes.simpleLruMap.Keys() {
374 value, ok := s.lruAttributes.simpleLruMap.Get(key)
376 keyStr := key.(string)
377 attributes[keyStr] = value
383 func (s *Span) copyToCappedAttributes(attributes []Attribute) {
384 for _, a := range attributes {
385 s.lruAttributes.add(a.key, a.value)
389 func (s *Span) addChild() {
390 if !s.IsRecordingEvents() {
394 s.data.ChildSpanCount++
398 // AddAttributes sets attributes in the span.
400 // Existing attributes whose keys appear in the attributes parameter are overwritten.
401 func (s *Span) AddAttributes(attributes ...Attribute) {
402 if !s.IsRecordingEvents() {
406 s.copyToCappedAttributes(attributes)
410 // copyAttributes copies a slice of Attributes into a map.
411 func copyAttributes(m map[string]interface{}, attributes []Attribute) {
412 for _, a := range attributes {
417 func (s *Span) lazyPrintfInternal(attributes []Attribute, format string, a ...interface{}) {
419 msg := fmt.Sprintf(format, a...)
420 var m map[string]interface{}
422 if len(attributes) != 0 {
423 m = make(map[string]interface{})
424 copyAttributes(m, attributes)
426 s.annotations.add(Annotation{
434 func (s *Span) printStringInternal(attributes []Attribute, str string) {
436 var a map[string]interface{}
438 if len(attributes) != 0 {
439 a = make(map[string]interface{})
440 copyAttributes(a, attributes)
442 s.annotations.add(Annotation{
450 // Annotate adds an annotation with attributes.
451 // Attributes can be nil.
452 func (s *Span) Annotate(attributes []Attribute, str string) {
453 if !s.IsRecordingEvents() {
456 s.printStringInternal(attributes, str)
459 // Annotatef adds an annotation with attributes.
460 func (s *Span) Annotatef(attributes []Attribute, format string, a ...interface{}) {
461 if !s.IsRecordingEvents() {
464 s.lazyPrintfInternal(attributes, format, a...)
467 // AddMessageSendEvent adds a message send event to the span.
469 // messageID is an identifier for the message, which is recommended to be
470 // unique in this span and the same between the send event and the receive
471 // event (this allows to identify a message between the sender and receiver).
472 // For example, this could be a sequence id.
473 func (s *Span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
474 if !s.IsRecordingEvents() {
479 s.messageEvents.add(MessageEvent{
481 EventType: MessageEventTypeSent,
482 MessageID: messageID,
483 UncompressedByteSize: uncompressedByteSize,
484 CompressedByteSize: compressedByteSize,
489 // AddMessageReceiveEvent adds a message receive event to the span.
491 // messageID is an identifier for the message, which is recommended to be
492 // unique in this span and the same between the send event and the receive
493 // event (this allows to identify a message between the sender and receiver).
494 // For example, this could be a sequence id.
495 func (s *Span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
496 if !s.IsRecordingEvents() {
501 s.messageEvents.add(MessageEvent{
503 EventType: MessageEventTypeRecv,
504 MessageID: messageID,
505 UncompressedByteSize: uncompressedByteSize,
506 CompressedByteSize: compressedByteSize,
511 // AddLink adds a link to the span.
512 func (s *Span) AddLink(l Link) {
513 if !s.IsRecordingEvents() {
521 func (s *Span) String() string {
526 return fmt.Sprintf("span %s", s.spanContext.SpanID)
529 str := fmt.Sprintf("span %s %q", s.spanContext.SpanID, s.data.Name)
534 var config atomic.Value // access atomically
537 gen := &defaultIDGenerator{}
538 // initialize traceID and spanID generators.
540 for _, p := range []interface{}{
541 &rngSeed, &gen.traceIDAdd, &gen.nextSpanID, &gen.spanIDInc,
543 binary.Read(crand.Reader, binary.LittleEndian, p)
545 gen.traceIDRand = rand.New(rand.NewSource(rngSeed))
548 config.Store(&Config{
549 DefaultSampler: ProbabilitySampler(defaultSamplingProbability),
551 MaxAttributesPerSpan: DefaultMaxAttributesPerSpan,
552 MaxAnnotationEventsPerSpan: DefaultMaxAnnotationEventsPerSpan,
553 MaxMessageEventsPerSpan: DefaultMaxMessageEventsPerSpan,
554 MaxLinksPerSpan: DefaultMaxLinksPerSpan,
558 type defaultIDGenerator struct {
561 // Please keep these as the first fields
562 // so that these 8 byte fields will be aligned on addresses
563 // divisible by 8, on both 32-bit and 64-bit machines when
564 // performing atomic increments and accesses.
566 // * https://github.com/census-instrumentation/opencensus-go/issues/587
567 // * https://github.com/census-instrumentation/opencensus-go/issues/865
568 // * https://golang.org/pkg/sync/atomic/#pkg-note-BUG
573 traceIDRand *rand.Rand
576 // NewSpanID returns a non-zero span ID from a randomly-chosen sequence.
577 func (gen *defaultIDGenerator) NewSpanID() [8]byte {
580 id = atomic.AddUint64(&gen.nextSpanID, gen.spanIDInc)
583 binary.LittleEndian.PutUint64(sid[:], id)
587 // NewTraceID returns a non-zero trace ID from a randomly-chosen sequence.
588 // mu should be held while this function is called.
589 func (gen *defaultIDGenerator) NewTraceID() [16]byte {
591 // Construct the trace ID from two outputs of traceIDRand, with a constant
592 // added to each half for additional entropy.
594 binary.LittleEndian.PutUint64(tid[0:8], gen.traceIDRand.Uint64()+gen.traceIDAdd[0])
595 binary.LittleEndian.PutUint64(tid[8:16], gen.traceIDRand.Uint64()+gen.traceIDAdd[1])