blob: 1785a4bbb0abefd8d24493bcbd41a1c6552b77a2 [file] [log] [blame]
Abhay Kumar40252eb2025-10-13 13:25:53 +00001// Copyright The OpenTelemetry Authors
2// SPDX-License-Identifier: Apache-2.0
3
4package trace // import "go.opentelemetry.io/otel/sdk/trace"
5
6import (
7 "context"
8 "fmt"
9 "reflect"
10 "runtime"
11 rt "runtime/trace"
12 "slices"
13 "strings"
14 "sync"
15 "time"
16 "unicode/utf8"
17
18 "go.opentelemetry.io/otel/attribute"
19 "go.opentelemetry.io/otel/codes"
20 "go.opentelemetry.io/otel/internal/global"
21 "go.opentelemetry.io/otel/sdk/instrumentation"
22 "go.opentelemetry.io/otel/sdk/resource"
23 semconv "go.opentelemetry.io/otel/semconv/v1.34.0"
24 "go.opentelemetry.io/otel/trace"
25 "go.opentelemetry.io/otel/trace/embedded"
26)
27
28// ReadOnlySpan allows reading information from the data structure underlying a
29// trace.Span. It is used in places where reading information from a span is
30// necessary but changing the span isn't necessary or allowed.
31//
32// Warning: methods may be added to this interface in minor releases.
33type ReadOnlySpan interface {
34 // Name returns the name of the span.
35 Name() string
36 // SpanContext returns the unique SpanContext that identifies the span.
37 SpanContext() trace.SpanContext
38 // Parent returns the unique SpanContext that identifies the parent of the
39 // span if one exists. If the span has no parent the returned SpanContext
40 // will be invalid.
41 Parent() trace.SpanContext
42 // SpanKind returns the role the span plays in a Trace.
43 SpanKind() trace.SpanKind
44 // StartTime returns the time the span started recording.
45 StartTime() time.Time
46 // EndTime returns the time the span stopped recording. It will be zero if
47 // the span has not ended.
48 EndTime() time.Time
49 // Attributes returns the defining attributes of the span.
50 // The order of the returned attributes is not guaranteed to be stable across invocations.
51 Attributes() []attribute.KeyValue
52 // Links returns all the links the span has to other spans.
53 Links() []Link
54 // Events returns all the events that occurred within in the spans
55 // lifetime.
56 Events() []Event
57 // Status returns the spans status.
58 Status() Status
59 // InstrumentationScope returns information about the instrumentation
60 // scope that created the span.
61 InstrumentationScope() instrumentation.Scope
62 // InstrumentationLibrary returns information about the instrumentation
63 // library that created the span.
64 // Deprecated: please use InstrumentationScope instead.
65 InstrumentationLibrary() instrumentation.Library //nolint:staticcheck // This method needs to be define for backwards compatibility
66 // Resource returns information about the entity that produced the span.
67 Resource() *resource.Resource
68 // DroppedAttributes returns the number of attributes dropped by the span
69 // due to limits being reached.
70 DroppedAttributes() int
71 // DroppedLinks returns the number of links dropped by the span due to
72 // limits being reached.
73 DroppedLinks() int
74 // DroppedEvents returns the number of events dropped by the span due to
75 // limits being reached.
76 DroppedEvents() int
77 // ChildSpanCount returns the count of spans that consider the span a
78 // direct parent.
79 ChildSpanCount() int
80
81 // A private method to prevent users implementing the
82 // interface and so future additions to it will not
83 // violate compatibility.
84 private()
85}
86
87// ReadWriteSpan exposes the same methods as trace.Span and in addition allows
88// reading information from the underlying data structure.
89// This interface exposes the union of the methods of trace.Span (which is a
90// "write-only" span) and ReadOnlySpan. New methods for writing or reading span
91// information should be added under trace.Span or ReadOnlySpan, respectively.
92//
93// Warning: methods may be added to this interface in minor releases.
94type ReadWriteSpan interface {
95 trace.Span
96 ReadOnlySpan
97}
98
99// recordingSpan is an implementation of the OpenTelemetry Span API
100// representing the individual component of a trace that is sampled.
101type recordingSpan struct {
102 embedded.Span
103
104 // mu protects the contents of this span.
105 mu sync.Mutex
106
107 // parent holds the parent span of this span as a trace.SpanContext.
108 parent trace.SpanContext
109
110 // spanKind represents the kind of this span as a trace.SpanKind.
111 spanKind trace.SpanKind
112
113 // name is the name of this span.
114 name string
115
116 // startTime is the time at which this span was started.
117 startTime time.Time
118
119 // endTime is the time at which this span was ended. It contains the zero
120 // value of time.Time until the span is ended.
121 endTime time.Time
122
123 // status is the status of this span.
124 status Status
125
126 // childSpanCount holds the number of child spans created for this span.
127 childSpanCount int
128
129 // spanContext holds the SpanContext of this span.
130 spanContext trace.SpanContext
131
132 // attributes is a collection of user provided key/values. The collection
133 // is constrained by a configurable maximum held by the parent
134 // TracerProvider. When additional attributes are added after this maximum
135 // is reached these attributes the user is attempting to add are dropped.
136 // This dropped number of attributes is tracked and reported in the
137 // ReadOnlySpan exported when the span ends.
138 attributes []attribute.KeyValue
139 droppedAttributes int
140 logDropAttrsOnce sync.Once
141
142 // events are stored in FIFO queue capped by configured limit.
143 events evictedQueue[Event]
144
145 // links are stored in FIFO queue capped by configured limit.
146 links evictedQueue[Link]
147
148 // executionTracerTaskEnd ends the execution tracer span.
149 executionTracerTaskEnd func()
150
151 // tracer is the SDK tracer that created this span.
152 tracer *tracer
153}
154
155var (
156 _ ReadWriteSpan = (*recordingSpan)(nil)
157 _ runtimeTracer = (*recordingSpan)(nil)
158)
159
160// SpanContext returns the SpanContext of this span.
161func (s *recordingSpan) SpanContext() trace.SpanContext {
162 if s == nil {
163 return trace.SpanContext{}
164 }
165 return s.spanContext
166}
167
168// IsRecording returns if this span is being recorded. If this span has ended
169// this will return false.
170func (s *recordingSpan) IsRecording() bool {
171 if s == nil {
172 return false
173 }
174 s.mu.Lock()
175 defer s.mu.Unlock()
176
177 return s.isRecording()
178}
179
180// isRecording returns if this span is being recorded. If this span has ended
181// this will return false.
182//
183// This method assumes s.mu.Lock is held by the caller.
184func (s *recordingSpan) isRecording() bool {
185 if s == nil {
186 return false
187 }
188 return s.endTime.IsZero()
189}
190
191// SetStatus sets the status of the Span in the form of a code and a
192// description, overriding previous values set. The description is only
193// included in the set status when the code is for an error. If this span is
194// not being recorded than this method does nothing.
195func (s *recordingSpan) SetStatus(code codes.Code, description string) {
196 if s == nil {
197 return
198 }
199
200 s.mu.Lock()
201 defer s.mu.Unlock()
202 if !s.isRecording() {
203 return
204 }
205 if s.status.Code > code {
206 return
207 }
208
209 status := Status{Code: code}
210 if code == codes.Error {
211 status.Description = description
212 }
213
214 s.status = status
215}
216
217// SetAttributes sets attributes of this span.
218//
219// If a key from attributes already exists the value associated with that key
220// will be overwritten with the value contained in attributes.
221//
222// If this span is not being recorded than this method does nothing.
223//
224// If adding attributes to the span would exceed the maximum amount of
225// attributes the span is configured to have, the last added attributes will
226// be dropped.
227func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) {
228 if s == nil || len(attributes) == 0 {
229 return
230 }
231
232 s.mu.Lock()
233 defer s.mu.Unlock()
234 if !s.isRecording() {
235 return
236 }
237
238 limit := s.tracer.provider.spanLimits.AttributeCountLimit
239 if limit == 0 {
240 // No attributes allowed.
241 s.addDroppedAttr(len(attributes))
242 return
243 }
244
245 // If adding these attributes could exceed the capacity of s perform a
246 // de-duplication and truncation while adding to avoid over allocation.
247 if limit > 0 && len(s.attributes)+len(attributes) > limit {
248 s.addOverCapAttrs(limit, attributes)
249 return
250 }
251
252 // Otherwise, add without deduplication. When attributes are read they
253 // will be deduplicated, optimizing the operation.
254 s.attributes = slices.Grow(s.attributes, len(attributes))
255 for _, a := range attributes {
256 if !a.Valid() {
257 // Drop all invalid attributes.
258 s.addDroppedAttr(1)
259 continue
260 }
261 a = truncateAttr(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a)
262 s.attributes = append(s.attributes, a)
263 }
264}
265
266// Declared as a var so tests can override.
267var logDropAttrs = func() {
268 global.Warn("limit reached: dropping trace Span attributes")
269}
270
271// addDroppedAttr adds incr to the count of dropped attributes.
272//
273// The first, and only the first, time this method is called a warning will be
274// logged.
275//
276// This method assumes s.mu.Lock is held by the caller.
277func (s *recordingSpan) addDroppedAttr(incr int) {
278 s.droppedAttributes += incr
279 s.logDropAttrsOnce.Do(logDropAttrs)
280}
281
282// addOverCapAttrs adds the attributes attrs to the span s while
283// de-duplicating the attributes of s and attrs and dropping attributes that
284// exceed the limit.
285//
286// This method assumes s.mu.Lock is held by the caller.
287//
288// This method should only be called when there is a possibility that adding
289// attrs to s will exceed the limit. Otherwise, attrs should be added to s
290// without checking for duplicates and all retrieval methods of the attributes
291// for s will de-duplicate as needed.
292//
293// This method assumes limit is a value > 0. The argument should be validated
294// by the caller.
295func (s *recordingSpan) addOverCapAttrs(limit int, attrs []attribute.KeyValue) {
296 // In order to not allocate more capacity to s.attributes than needed,
297 // prune and truncate this addition of attributes while adding.
298
299 // Do not set a capacity when creating this map. Benchmark testing has
300 // showed this to only add unused memory allocations in general use.
301 exists := make(map[attribute.Key]int, len(s.attributes))
302 s.dedupeAttrsFromRecord(exists)
303
304 // Now that s.attributes is deduplicated, adding unique attributes up to
305 // the capacity of s will not over allocate s.attributes.
306
307 // max size = limit
308 maxCap := min(len(attrs)+len(s.attributes), limit)
309 if cap(s.attributes) < maxCap {
310 s.attributes = slices.Grow(s.attributes, maxCap-cap(s.attributes))
311 }
312 for _, a := range attrs {
313 if !a.Valid() {
314 // Drop all invalid attributes.
315 s.addDroppedAttr(1)
316 continue
317 }
318
319 if idx, ok := exists[a.Key]; ok {
320 // Perform all updates before dropping, even when at capacity.
321 a = truncateAttr(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a)
322 s.attributes[idx] = a
323 continue
324 }
325
326 if len(s.attributes) >= limit {
327 // Do not just drop all of the remaining attributes, make sure
328 // updates are checked and performed.
329 s.addDroppedAttr(1)
330 } else {
331 a = truncateAttr(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a)
332 s.attributes = append(s.attributes, a)
333 exists[a.Key] = len(s.attributes) - 1
334 }
335 }
336}
337
338// truncateAttr returns a truncated version of attr. Only string and string
339// slice attribute values are truncated. String values are truncated to at
340// most a length of limit. Each string slice value is truncated in this fashion
341// (the slice length itself is unaffected).
342//
343// No truncation is performed for a negative limit.
344func truncateAttr(limit int, attr attribute.KeyValue) attribute.KeyValue {
345 if limit < 0 {
346 return attr
347 }
348 switch attr.Value.Type() {
349 case attribute.STRING:
350 v := attr.Value.AsString()
351 return attr.Key.String(truncate(limit, v))
352 case attribute.STRINGSLICE:
353 v := attr.Value.AsStringSlice()
354 for i := range v {
355 v[i] = truncate(limit, v[i])
356 }
357 return attr.Key.StringSlice(v)
358 }
359 return attr
360}
361
362// truncate returns a truncated version of s such that it contains less than
363// the limit number of characters. Truncation is applied by returning the limit
364// number of valid characters contained in s.
365//
366// If limit is negative, it returns the original string.
367//
368// UTF-8 is supported. When truncating, all invalid characters are dropped
369// before applying truncation.
370//
371// If s already contains less than the limit number of bytes, it is returned
372// unchanged. No invalid characters are removed.
373func truncate(limit int, s string) string {
374 // This prioritize performance in the following order based on the most
375 // common expected use-cases.
376 //
377 // - Short values less than the default limit (128).
378 // - Strings with valid encodings that exceed the limit.
379 // - No limit.
380 // - Strings with invalid encodings that exceed the limit.
381 if limit < 0 || len(s) <= limit {
382 return s
383 }
384
385 // Optimistically, assume all valid UTF-8.
386 var b strings.Builder
387 count := 0
388 for i, c := range s {
389 if c != utf8.RuneError {
390 count++
391 if count > limit {
392 return s[:i]
393 }
394 continue
395 }
396
397 _, size := utf8.DecodeRuneInString(s[i:])
398 if size == 1 {
399 // Invalid encoding.
400 b.Grow(len(s) - 1)
401 _, _ = b.WriteString(s[:i])
402 s = s[i:]
403 break
404 }
405 }
406
407 // Fast-path, no invalid input.
408 if b.Cap() == 0 {
409 return s
410 }
411
412 // Truncate while validating UTF-8.
413 for i := 0; i < len(s) && count < limit; {
414 c := s[i]
415 if c < utf8.RuneSelf {
416 // Optimization for single byte runes (common case).
417 _ = b.WriteByte(c)
418 i++
419 count++
420 continue
421 }
422
423 _, size := utf8.DecodeRuneInString(s[i:])
424 if size == 1 {
425 // We checked for all 1-byte runes above, this is a RuneError.
426 i++
427 continue
428 }
429
430 _, _ = b.WriteString(s[i : i+size])
431 i += size
432 count++
433 }
434
435 return b.String()
436}
437
438// End ends the span. This method does nothing if the span is already ended or
439// is not being recorded.
440//
441// The only SpanEndOption currently supported are [trace.WithTimestamp], and
442// [trace.WithStackTrace].
443//
444// If this method is called while panicking an error event is added to the
445// Span before ending it and the panic is continued.
446func (s *recordingSpan) End(options ...trace.SpanEndOption) {
447 // Do not start by checking if the span is being recorded which requires
448 // acquiring a lock. Make a minimal check that the span is not nil.
449 if s == nil {
450 return
451 }
452
453 // Store the end time as soon as possible to avoid artificially increasing
454 // the span's duration in case some operation below takes a while.
455 et := monotonicEndTime(s.startTime)
456
457 // Lock the span now that we have an end time and see if we need to do any more processing.
458 s.mu.Lock()
459 if !s.isRecording() {
460 s.mu.Unlock()
461 return
462 }
463
464 config := trace.NewSpanEndConfig(options...)
465 if recovered := recover(); recovered != nil {
466 // Record but don't stop the panic.
467 defer panic(recovered)
468 opts := []trace.EventOption{
469 trace.WithAttributes(
470 semconv.ExceptionType(typeStr(recovered)),
471 semconv.ExceptionMessage(fmt.Sprint(recovered)),
472 ),
473 }
474
475 if config.StackTrace() {
476 opts = append(opts, trace.WithAttributes(
477 semconv.ExceptionStacktrace(recordStackTrace()),
478 ))
479 }
480
481 s.addEvent(semconv.ExceptionEventName, opts...)
482 }
483
484 if s.executionTracerTaskEnd != nil {
485 s.mu.Unlock()
486 s.executionTracerTaskEnd()
487 s.mu.Lock()
488 }
489
490 // Setting endTime to non-zero marks the span as ended and not recording.
491 if config.Timestamp().IsZero() {
492 s.endTime = et
493 } else {
494 s.endTime = config.Timestamp()
495 }
496 s.mu.Unlock()
497
498 sps := s.tracer.provider.getSpanProcessors()
499 if len(sps) == 0 {
500 return
501 }
502 snap := s.snapshot()
503 for _, sp := range sps {
504 sp.sp.OnEnd(snap)
505 }
506}
507
508// monotonicEndTime returns the end time at present but offset from start,
509// monotonically.
510//
511// The monotonic clock is used in subtractions hence the duration since start
512// added back to start gives end as a monotonic time. See
513// https://golang.org/pkg/time/#hdr-Monotonic_Clocks
514func monotonicEndTime(start time.Time) time.Time {
515 return start.Add(time.Since(start))
516}
517
518// RecordError will record err as a span event for this span. An additional call to
519// SetStatus is required if the Status of the Span should be set to Error, this method
520// does not change the Span status. If this span is not being recorded or err is nil
521// than this method does nothing.
522func (s *recordingSpan) RecordError(err error, opts ...trace.EventOption) {
523 if s == nil || err == nil {
524 return
525 }
526
527 s.mu.Lock()
528 defer s.mu.Unlock()
529 if !s.isRecording() {
530 return
531 }
532
533 opts = append(opts, trace.WithAttributes(
534 semconv.ExceptionType(typeStr(err)),
535 semconv.ExceptionMessage(err.Error()),
536 ))
537
538 c := trace.NewEventConfig(opts...)
539 if c.StackTrace() {
540 opts = append(opts, trace.WithAttributes(
541 semconv.ExceptionStacktrace(recordStackTrace()),
542 ))
543 }
544
545 s.addEvent(semconv.ExceptionEventName, opts...)
546}
547
548func typeStr(i interface{}) string {
549 t := reflect.TypeOf(i)
550 if t.PkgPath() == "" && t.Name() == "" {
551 // Likely a builtin type.
552 return t.String()
553 }
554 return fmt.Sprintf("%s.%s", t.PkgPath(), t.Name())
555}
556
557func recordStackTrace() string {
558 stackTrace := make([]byte, 2048)
559 n := runtime.Stack(stackTrace, false)
560
561 return string(stackTrace[0:n])
562}
563
564// AddEvent adds an event with the provided name and options. If this span is
565// not being recorded then this method does nothing.
566func (s *recordingSpan) AddEvent(name string, o ...trace.EventOption) {
567 if s == nil {
568 return
569 }
570
571 s.mu.Lock()
572 defer s.mu.Unlock()
573 if !s.isRecording() {
574 return
575 }
576 s.addEvent(name, o...)
577}
578
579// addEvent adds an event with the provided name and options.
580//
581// This method assumes s.mu.Lock is held by the caller.
582func (s *recordingSpan) addEvent(name string, o ...trace.EventOption) {
583 c := trace.NewEventConfig(o...)
584 e := Event{Name: name, Attributes: c.Attributes(), Time: c.Timestamp()}
585
586 // Discard attributes over limit.
587 limit := s.tracer.provider.spanLimits.AttributePerEventCountLimit
588 if limit == 0 {
589 // Drop all attributes.
590 e.DroppedAttributeCount = len(e.Attributes)
591 e.Attributes = nil
592 } else if limit > 0 && len(e.Attributes) > limit {
593 // Drop over capacity.
594 e.DroppedAttributeCount = len(e.Attributes) - limit
595 e.Attributes = e.Attributes[:limit]
596 }
597
598 s.events.add(e)
599}
600
601// SetName sets the name of this span. If this span is not being recorded than
602// this method does nothing.
603func (s *recordingSpan) SetName(name string) {
604 if s == nil {
605 return
606 }
607
608 s.mu.Lock()
609 defer s.mu.Unlock()
610 if !s.isRecording() {
611 return
612 }
613 s.name = name
614}
615
616// Name returns the name of this span.
617func (s *recordingSpan) Name() string {
618 s.mu.Lock()
619 defer s.mu.Unlock()
620 return s.name
621}
622
623// Name returns the SpanContext of this span's parent span.
624func (s *recordingSpan) Parent() trace.SpanContext {
625 s.mu.Lock()
626 defer s.mu.Unlock()
627 return s.parent
628}
629
630// SpanKind returns the SpanKind of this span.
631func (s *recordingSpan) SpanKind() trace.SpanKind {
632 s.mu.Lock()
633 defer s.mu.Unlock()
634 return s.spanKind
635}
636
637// StartTime returns the time this span started.
638func (s *recordingSpan) StartTime() time.Time {
639 s.mu.Lock()
640 defer s.mu.Unlock()
641 return s.startTime
642}
643
644// EndTime returns the time this span ended. For spans that have not yet
645// ended, the returned value will be the zero value of time.Time.
646func (s *recordingSpan) EndTime() time.Time {
647 s.mu.Lock()
648 defer s.mu.Unlock()
649 return s.endTime
650}
651
652// Attributes returns the attributes of this span.
653//
654// The order of the returned attributes is not guaranteed to be stable.
655func (s *recordingSpan) Attributes() []attribute.KeyValue {
656 s.mu.Lock()
657 defer s.mu.Unlock()
658 s.dedupeAttrs()
659 return s.attributes
660}
661
662// dedupeAttrs deduplicates the attributes of s to fit capacity.
663//
664// This method assumes s.mu.Lock is held by the caller.
665func (s *recordingSpan) dedupeAttrs() {
666 // Do not set a capacity when creating this map. Benchmark testing has
667 // showed this to only add unused memory allocations in general use.
668 exists := make(map[attribute.Key]int, len(s.attributes))
669 s.dedupeAttrsFromRecord(exists)
670}
671
672// dedupeAttrsFromRecord deduplicates the attributes of s to fit capacity
673// using record as the record of unique attribute keys to their index.
674//
675// This method assumes s.mu.Lock is held by the caller.
676func (s *recordingSpan) dedupeAttrsFromRecord(record map[attribute.Key]int) {
677 // Use the fact that slices share the same backing array.
678 unique := s.attributes[:0]
679 for _, a := range s.attributes {
680 if idx, ok := record[a.Key]; ok {
681 unique[idx] = a
682 } else {
683 unique = append(unique, a)
684 record[a.Key] = len(unique) - 1
685 }
686 }
687 clear(s.attributes[len(unique):]) // Erase unneeded elements to let GC collect objects.
688 s.attributes = unique
689}
690
691// Links returns the links of this span.
692func (s *recordingSpan) Links() []Link {
693 s.mu.Lock()
694 defer s.mu.Unlock()
695 if len(s.links.queue) == 0 {
696 return []Link{}
697 }
698 return s.links.copy()
699}
700
701// Events returns the events of this span.
702func (s *recordingSpan) Events() []Event {
703 s.mu.Lock()
704 defer s.mu.Unlock()
705 if len(s.events.queue) == 0 {
706 return []Event{}
707 }
708 return s.events.copy()
709}
710
711// Status returns the status of this span.
712func (s *recordingSpan) Status() Status {
713 s.mu.Lock()
714 defer s.mu.Unlock()
715 return s.status
716}
717
718// InstrumentationScope returns the instrumentation.Scope associated with
719// the Tracer that created this span.
720func (s *recordingSpan) InstrumentationScope() instrumentation.Scope {
721 s.mu.Lock()
722 defer s.mu.Unlock()
723 return s.tracer.instrumentationScope
724}
725
726// InstrumentationLibrary returns the instrumentation.Library associated with
727// the Tracer that created this span.
728func (s *recordingSpan) InstrumentationLibrary() instrumentation.Library { //nolint:staticcheck // This method needs to be define for backwards compatibility
729 s.mu.Lock()
730 defer s.mu.Unlock()
731 return s.tracer.instrumentationScope
732}
733
734// Resource returns the Resource associated with the Tracer that created this
735// span.
736func (s *recordingSpan) Resource() *resource.Resource {
737 s.mu.Lock()
738 defer s.mu.Unlock()
739 return s.tracer.provider.resource
740}
741
742func (s *recordingSpan) AddLink(link trace.Link) {
743 if s == nil {
744 return
745 }
746 if !link.SpanContext.IsValid() && len(link.Attributes) == 0 &&
747 link.SpanContext.TraceState().Len() == 0 {
748 return
749 }
750
751 s.mu.Lock()
752 defer s.mu.Unlock()
753 if !s.isRecording() {
754 return
755 }
756
757 l := Link{SpanContext: link.SpanContext, Attributes: link.Attributes}
758
759 // Discard attributes over limit.
760 limit := s.tracer.provider.spanLimits.AttributePerLinkCountLimit
761 if limit == 0 {
762 // Drop all attributes.
763 l.DroppedAttributeCount = len(l.Attributes)
764 l.Attributes = nil
765 } else if limit > 0 && len(l.Attributes) > limit {
766 l.DroppedAttributeCount = len(l.Attributes) - limit
767 l.Attributes = l.Attributes[:limit]
768 }
769
770 s.links.add(l)
771}
772
773// DroppedAttributes returns the number of attributes dropped by the span
774// due to limits being reached.
775func (s *recordingSpan) DroppedAttributes() int {
776 s.mu.Lock()
777 defer s.mu.Unlock()
778 return s.droppedAttributes
779}
780
781// DroppedLinks returns the number of links dropped by the span due to limits
782// being reached.
783func (s *recordingSpan) DroppedLinks() int {
784 s.mu.Lock()
785 defer s.mu.Unlock()
786 return s.links.droppedCount
787}
788
789// DroppedEvents returns the number of events dropped by the span due to
790// limits being reached.
791func (s *recordingSpan) DroppedEvents() int {
792 s.mu.Lock()
793 defer s.mu.Unlock()
794 return s.events.droppedCount
795}
796
797// ChildSpanCount returns the count of spans that consider the span a
798// direct parent.
799func (s *recordingSpan) ChildSpanCount() int {
800 s.mu.Lock()
801 defer s.mu.Unlock()
802 return s.childSpanCount
803}
804
805// TracerProvider returns a trace.TracerProvider that can be used to generate
806// additional Spans on the same telemetry pipeline as the current Span.
807func (s *recordingSpan) TracerProvider() trace.TracerProvider {
808 return s.tracer.provider
809}
810
811// snapshot creates a read-only copy of the current state of the span.
812func (s *recordingSpan) snapshot() ReadOnlySpan {
813 var sd snapshot
814 s.mu.Lock()
815 defer s.mu.Unlock()
816
817 sd.endTime = s.endTime
818 sd.instrumentationScope = s.tracer.instrumentationScope
819 sd.name = s.name
820 sd.parent = s.parent
821 sd.resource = s.tracer.provider.resource
822 sd.spanContext = s.spanContext
823 sd.spanKind = s.spanKind
824 sd.startTime = s.startTime
825 sd.status = s.status
826 sd.childSpanCount = s.childSpanCount
827
828 if len(s.attributes) > 0 {
829 s.dedupeAttrs()
830 sd.attributes = s.attributes
831 }
832 sd.droppedAttributeCount = s.droppedAttributes
833 if len(s.events.queue) > 0 {
834 sd.events = s.events.copy()
835 sd.droppedEventCount = s.events.droppedCount
836 }
837 if len(s.links.queue) > 0 {
838 sd.links = s.links.copy()
839 sd.droppedLinkCount = s.links.droppedCount
840 }
841 return &sd
842}
843
844func (s *recordingSpan) addChild() {
845 if s == nil {
846 return
847 }
848
849 s.mu.Lock()
850 defer s.mu.Unlock()
851 if !s.isRecording() {
852 return
853 }
854 s.childSpanCount++
855}
856
857func (*recordingSpan) private() {}
858
859// runtimeTrace starts a "runtime/trace".Task for the span and returns a
860// context containing the task.
861func (s *recordingSpan) runtimeTrace(ctx context.Context) context.Context {
862 if !rt.IsEnabled() {
863 // Avoid additional overhead if runtime/trace is not enabled.
864 return ctx
865 }
866 nctx, task := rt.NewTask(ctx, s.name)
867
868 s.mu.Lock()
869 s.executionTracerTaskEnd = task.End
870 s.mu.Unlock()
871
872 return nctx
873}
874
875// nonRecordingSpan is a minimal implementation of the OpenTelemetry Span API
876// that wraps a SpanContext. It performs no operations other than to return
877// the wrapped SpanContext or TracerProvider that created it.
878type nonRecordingSpan struct {
879 embedded.Span
880
881 // tracer is the SDK tracer that created this span.
882 tracer *tracer
883 sc trace.SpanContext
884}
885
886var _ trace.Span = nonRecordingSpan{}
887
888// SpanContext returns the wrapped SpanContext.
889func (s nonRecordingSpan) SpanContext() trace.SpanContext { return s.sc }
890
891// IsRecording always returns false.
892func (nonRecordingSpan) IsRecording() bool { return false }
893
894// SetStatus does nothing.
895func (nonRecordingSpan) SetStatus(codes.Code, string) {}
896
897// SetError does nothing.
898func (nonRecordingSpan) SetError(bool) {}
899
900// SetAttributes does nothing.
901func (nonRecordingSpan) SetAttributes(...attribute.KeyValue) {}
902
903// End does nothing.
904func (nonRecordingSpan) End(...trace.SpanEndOption) {}
905
906// RecordError does nothing.
907func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {}
908
909// AddEvent does nothing.
910func (nonRecordingSpan) AddEvent(string, ...trace.EventOption) {}
911
912// AddLink does nothing.
913func (nonRecordingSpan) AddLink(trace.Link) {}
914
915// SetName does nothing.
916func (nonRecordingSpan) SetName(string) {}
917
918// TracerProvider returns the trace.TracerProvider that provided the Tracer
919// that created this span.
920func (s nonRecordingSpan) TracerProvider() trace.TracerProvider { return s.tracer.provider }
921
922func isRecording(s SamplingResult) bool {
923 return s.Decision == RecordOnly || s.Decision == RecordAndSample
924}
925
926func isSampled(s SamplingResult) bool {
927 return s.Decision == RecordAndSample
928}
929
930// Status is the classified state of a Span.
931type Status struct {
932 // Code is an identifier of a Spans state classification.
933 Code codes.Code
934 // Description is a user hint about why that status was set. It is only
935 // applicable when Code is Error.
936 Description string
937}