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