2020-03-24 07:41:10 +02:00
// Copyright The OpenTelemetry Authors
2024-02-29 08:05:28 +02:00
// SPDX-License-Identifier: Apache-2.0
2019-08-02 22:52:55 +02:00
2020-11-04 19:10:58 +02:00
package trace // import "go.opentelemetry.io/otel/sdk/trace"
2019-08-02 22:52:55 +02:00
import (
2020-12-10 03:30:32 +02:00
"context"
2020-02-28 23:44:53 +02:00
"fmt"
"reflect"
2021-08-13 23:44:18 +02:00
"runtime"
2021-09-02 23:30:12 +02:00
rt "runtime/trace"
2024-02-25 20:48:32 +02:00
"slices"
2022-09-12 16:54:58 +02:00
"strings"
2019-08-02 22:52:55 +02:00
"sync"
"time"
2022-09-12 16:54:58 +02:00
"unicode/utf8"
2019-08-02 22:52:55 +02:00
2021-02-18 19:59:37 +02:00
"go.opentelemetry.io/otel/attribute"
2020-08-10 18:17:09 +02:00
"go.opentelemetry.io/otel/codes"
2024-05-30 20:40:08 +02:00
"go.opentelemetry.io/otel/internal/global"
2020-12-11 07:15:44 +02:00
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/resource"
2024-06-06 18:36:59 +02:00
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
2021-11-13 18:35:04 +02:00
"go.opentelemetry.io/otel/trace"
2023-10-19 19:16:24 +02:00
"go.opentelemetry.io/otel/trace/embedded"
2019-08-02 22:52:55 +02:00
)
2020-12-11 07:15:44 +02:00
// ReadOnlySpan allows reading information from the data structure underlying a
// trace.Span. It is used in places where reading information from a span is
// necessary but changing the span isn't necessary or allowed.
2021-06-18 16:56:11 +02:00
//
// Warning: methods may be added to this interface in minor releases.
2020-12-11 07:15:44 +02:00
type ReadOnlySpan interface {
2021-05-05 01:45:13 +02:00
// Name returns the name of the span.
2020-12-11 07:15:44 +02:00
Name ( ) string
2021-05-05 01:45:13 +02:00
// SpanContext returns the unique SpanContext that identifies the span.
2020-12-11 07:15:44 +02:00
SpanContext ( ) trace . SpanContext
2021-05-05 01:45:13 +02:00
// Parent returns the unique SpanContext that identifies the parent of the
// span if one exists. If the span has no parent the returned SpanContext
// will be invalid.
2020-12-11 07:15:44 +02:00
Parent ( ) trace . SpanContext
2021-05-05 01:45:13 +02:00
// SpanKind returns the role the span plays in a Trace.
2020-12-11 07:15:44 +02:00
SpanKind ( ) trace . SpanKind
2021-05-05 01:45:13 +02:00
// StartTime returns the time the span started recording.
2020-12-11 07:15:44 +02:00
StartTime ( ) time . Time
2021-05-05 01:45:13 +02:00
// EndTime returns the time the span stopped recording. It will be zero if
// the span has not ended.
2020-12-11 07:15:44 +02:00
EndTime ( ) time . Time
2021-05-05 01:45:13 +02:00
// Attributes returns the defining attributes of the span.
2022-02-07 22:58:05 +02:00
// The order of the returned attributes is not guaranteed to be stable across invocations.
2021-02-18 19:59:37 +02:00
Attributes ( ) [ ] attribute . KeyValue
2021-05-05 01:45:13 +02:00
// Links returns all the links the span has to other spans.
2021-07-26 17:06:41 +02:00
Links ( ) [ ] Link
2021-05-05 01:45:13 +02:00
// Events returns all the events that occurred within in the spans
// lifetime.
2021-04-29 19:29:48 +02:00
Events ( ) [ ] Event
2021-05-05 01:45:13 +02:00
// Status returns the spans status.
2021-05-03 21:00:54 +02:00
Status ( ) Status
2022-07-06 20:55:46 +02:00
// InstrumentationScope returns information about the instrumentation
// scope that created the span.
InstrumentationScope ( ) instrumentation . Scope
2021-05-05 01:45:13 +02:00
// InstrumentationLibrary returns information about the instrumentation
// library that created the span.
2022-07-06 20:55:46 +02:00
// Deprecated: please use InstrumentationScope instead.
2024-07-24 09:33:07 +02:00
InstrumentationLibrary ( ) instrumentation . Library //nolint:staticcheck // This method needs to be define for backwards compatibility
2021-05-05 01:45:13 +02:00
// Resource returns information about the entity that produced the span.
2020-12-11 07:15:44 +02:00
Resource ( ) * resource . Resource
2021-05-05 01:45:13 +02:00
// DroppedAttributes returns the number of attributes dropped by the span
// due to limits being reached.
DroppedAttributes ( ) int
// DroppedLinks returns the number of links dropped by the span due to
// limits being reached.
DroppedLinks ( ) int
// DroppedEvents returns the number of events dropped by the span due to
// limits being reached.
DroppedEvents ( ) int
// ChildSpanCount returns the count of spans that consider the span a
// direct parent.
ChildSpanCount ( ) int
2021-02-24 20:03:35 +02:00
// A private method to prevent users implementing the
// interface and so future additions to it will not
// violate compatibility.
private ( )
2020-12-11 07:15:44 +02:00
}
// ReadWriteSpan exposes the same methods as trace.Span and in addition allows
// reading information from the underlying data structure.
// This interface exposes the union of the methods of trace.Span (which is a
// "write-only" span) and ReadOnlySpan. New methods for writing or reading span
// information should be added under trace.Span or ReadOnlySpan, respectively.
2021-06-18 16:56:11 +02:00
//
// Warning: methods may be added to this interface in minor releases.
2020-12-11 07:15:44 +02:00
type ReadWriteSpan interface {
trace . Span
ReadOnlySpan
}
2021-09-02 23:30:12 +02:00
// recordingSpan is an implementation of the OpenTelemetry Span API
// representing the individual component of a trace that is sampled.
type recordingSpan struct {
2023-10-19 19:16:24 +02:00
embedded . Span
2020-11-09 20:40:02 +02:00
// mu protects the contents of this span.
mu sync . Mutex
2020-12-11 07:15:44 +02:00
// parent holds the parent span of this span as a trace.SpanContext.
parent trace . SpanContext
// spanKind represents the kind of this span as a trace.SpanKind.
spanKind trace . SpanKind
// name is the name of this span.
name string
// startTime is the time at which this span was started.
startTime time . Time
// endTime is the time at which this span was ended. It contains the zero
// value of time.Time until the span is ended.
endTime time . Time
2021-05-03 21:00:54 +02:00
// status is the status of this span.
status Status
2020-12-11 07:15:44 +02:00
// childSpanCount holds the number of child spans created for this span.
childSpanCount int
// spanContext holds the SpanContext of this span.
2020-11-07 00:13:31 +02:00
spanContext trace . SpanContext
2019-08-02 22:52:55 +02:00
2022-02-07 22:58:05 +02:00
// attributes is a collection of user provided key/values. The collection
// is constrained by a configurable maximum held by the parent
// TracerProvider. When additional attributes are added after this maximum
// is reached these attributes the user is attempting to add are dropped.
// This dropped number of attributes is tracked and reported in the
// ReadOnlySpan exported when the span ends.
attributes [ ] attribute . KeyValue
droppedAttributes int
2024-05-30 20:40:08 +02:00
logDropAttrsOnce sync . Once
2019-08-02 22:52:55 +02:00
2021-05-05 01:45:13 +02:00
// events are stored in FIFO queue capped by configured limit.
2024-05-30 20:40:08 +02:00
events evictedQueue [ Event ]
2019-08-02 22:52:55 +02:00
// links are stored in FIFO queue capped by configured limit.
2024-05-30 20:40:08 +02:00
links evictedQueue [ Link ]
2019-08-02 22:52:55 +02:00
2020-11-09 20:40:02 +02:00
// executionTracerTaskEnd ends the execution tracer span.
executionTracerTaskEnd func ( )
// tracer is the SDK tracer that created this span.
tracer * tracer
2019-08-02 22:52:55 +02:00
}
2023-10-16 19:02:21 +02:00
var (
_ ReadWriteSpan = ( * recordingSpan ) ( nil )
_ runtimeTracer = ( * recordingSpan ) ( nil )
)
2019-08-02 22:52:55 +02:00
2021-02-17 16:41:18 +02:00
// SpanContext returns the SpanContext of this span.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) SpanContext ( ) trace . SpanContext {
2019-08-02 22:52:55 +02:00
if s == nil {
2020-11-07 00:13:31 +02:00
return trace . SpanContext { }
2019-08-02 22:52:55 +02:00
}
return s . spanContext
}
2021-02-17 16:41:18 +02:00
// IsRecording returns if this span is being recorded. If this span has ended
// this will return false.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) IsRecording ( ) bool {
2019-08-02 22:52:55 +02:00
if s == nil {
return false
}
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
2021-03-30 22:26:42 +02:00
2024-10-07 09:30:29 +02:00
return s . isRecording ( )
}
// isRecording returns if this span is being recorded. If this span has ended
// this will return false.
2024-10-09 09:51:17 +02:00
//
// This method assumes s.mu.Lock is held by the caller.
2024-10-07 09:30:29 +02:00
func ( s * recordingSpan ) isRecording ( ) bool {
if s == nil {
return false
}
2021-09-02 23:30:12 +02:00
return s . endTime . IsZero ( )
2019-08-02 22:52:55 +02:00
}
2021-05-03 21:00:54 +02:00
// SetStatus sets the status of the Span in the form of a code and a
// description, overriding previous values set. The description is only
// included in the set status when the code is for an error. If this span is
// not being recorded than this method does nothing.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) SetStatus ( code codes . Code , description string ) {
2024-10-07 09:30:29 +02:00
if s == nil {
2019-08-02 22:52:55 +02:00
return
}
2024-10-07 09:30:29 +02:00
2022-09-23 20:39:53 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
2024-10-07 09:30:29 +02:00
if ! s . isRecording ( ) {
return
}
2022-09-23 20:39:53 +02:00
if s . status . Code > code {
return
}
2021-05-03 21:00:54 +02:00
status := Status { Code : code }
2021-03-08 19:40:38 +02:00
if code == codes . Error {
2021-05-03 21:00:54 +02:00
status . Description = description
2021-03-08 19:40:38 +02:00
}
2021-05-03 21:00:54 +02:00
s . status = status
2019-08-02 22:52:55 +02:00
}
2021-02-17 16:41:18 +02:00
// SetAttributes sets attributes of this span.
//
// If a key from attributes already exists the value associated with that key
// will be overwritten with the value contained in attributes.
//
// If this span is not being recorded than this method does nothing.
2022-02-07 22:58:05 +02:00
//
// If adding attributes to the span would exceed the maximum amount of
// attributes the span is configured to have, the last added attributes will
// be dropped.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) SetAttributes ( attributes ... attribute . KeyValue ) {
2024-10-07 09:30:29 +02:00
if s == nil || len ( attributes ) == 0 {
2019-08-02 22:52:55 +02:00
return
}
2022-02-07 22:58:05 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
2024-10-07 09:30:29 +02:00
if ! s . isRecording ( ) {
return
}
2022-02-07 22:58:05 +02:00
2022-03-03 17:56:07 +02:00
limit := s . tracer . provider . spanLimits . AttributeCountLimit
if limit == 0 {
// No attributes allowed.
2024-05-30 20:40:08 +02:00
s . addDroppedAttr ( len ( attributes ) )
2022-03-03 17:56:07 +02:00
return
}
2022-02-07 22:58:05 +02:00
// If adding these attributes could exceed the capacity of s perform a
// de-duplication and truncation while adding to avoid over allocation.
2022-03-03 17:56:07 +02:00
if limit > 0 && len ( s . attributes ) + len ( attributes ) > limit {
s . addOverCapAttrs ( limit , attributes )
2022-02-07 22:58:05 +02:00
return
}
// Otherwise, add without deduplication. When attributes are read they
// will be deduplicated, optimizing the operation.
2024-10-07 09:30:29 +02:00
s . attributes = slices . Grow ( s . attributes , len ( attributes ) )
2022-02-07 22:58:05 +02:00
for _ , a := range attributes {
if ! a . Valid ( ) {
// Drop all invalid attributes.
2024-05-30 20:40:08 +02:00
s . addDroppedAttr ( 1 )
2022-02-07 22:58:05 +02:00
continue
}
2022-03-03 17:56:07 +02:00
a = truncateAttr ( s . tracer . provider . spanLimits . AttributeValueLengthLimit , a )
2022-02-07 22:58:05 +02:00
s . attributes = append ( s . attributes , a )
}
}
2024-05-30 20:40:08 +02:00
// Declared as a var so tests can override.
var logDropAttrs = func ( ) {
global . Warn ( "limit reached: dropping trace Span attributes" )
}
// addDroppedAttr adds incr to the count of dropped attributes.
//
// The first, and only the first, time this method is called a warning will be
// logged.
//
// This method assumes s.mu.Lock is held by the caller.
func ( s * recordingSpan ) addDroppedAttr ( incr int ) {
s . droppedAttributes += incr
s . logDropAttrsOnce . Do ( logDropAttrs )
}
2022-02-07 22:58:05 +02:00
// addOverCapAttrs adds the attributes attrs to the span s while
// de-duplicating the attributes of s and attrs and dropping attributes that
2022-03-03 17:56:07 +02:00
// exceed the limit.
2022-02-07 22:58:05 +02:00
//
// This method assumes s.mu.Lock is held by the caller.
//
// This method should only be called when there is a possibility that adding
2022-03-03 17:56:07 +02:00
// attrs to s will exceed the limit. Otherwise, attrs should be added to s
// without checking for duplicates and all retrieval methods of the attributes
// for s will de-duplicate as needed.
//
// This method assumes limit is a value > 0. The argument should be validated
// by the caller.
func ( s * recordingSpan ) addOverCapAttrs ( limit int , attrs [ ] attribute . KeyValue ) {
2022-02-07 22:58:05 +02:00
// In order to not allocate more capacity to s.attributes than needed,
// prune and truncate this addition of attributes while adding.
// Do not set a capacity when creating this map. Benchmark testing has
// showed this to only add unused memory allocations in general use.
2024-10-07 09:30:29 +02:00
exists := make ( map [ attribute . Key ] int , len ( s . attributes ) )
s . dedupeAttrsFromRecord ( exists )
2022-02-07 22:58:05 +02:00
// Now that s.attributes is deduplicated, adding unique attributes up to
// the capacity of s will not over allocate s.attributes.
2024-10-07 09:30:29 +02:00
// max size = limit
maxCap := min ( len ( attrs ) + len ( s . attributes ) , limit )
if cap ( s . attributes ) < maxCap {
s . attributes = slices . Grow ( s . attributes , maxCap - cap ( s . attributes ) )
}
2022-02-07 22:58:05 +02:00
for _ , a := range attrs {
if ! a . Valid ( ) {
// Drop all invalid attributes.
2024-05-30 20:40:08 +02:00
s . addDroppedAttr ( 1 )
2022-02-07 22:58:05 +02:00
continue
}
if idx , ok := exists [ a . Key ] ; ok {
// Perform all updates before dropping, even when at capacity.
2024-10-07 09:30:29 +02:00
a = truncateAttr ( s . tracer . provider . spanLimits . AttributeValueLengthLimit , a )
2022-02-07 22:58:05 +02:00
s . attributes [ idx ] = a
continue
}
2022-03-03 17:56:07 +02:00
if len ( s . attributes ) >= limit {
2022-02-07 22:58:05 +02:00
// Do not just drop all of the remaining attributes, make sure
// updates are checked and performed.
2024-05-30 20:40:08 +02:00
s . addDroppedAttr ( 1 )
2022-02-07 22:58:05 +02:00
} else {
2022-03-03 17:56:07 +02:00
a = truncateAttr ( s . tracer . provider . spanLimits . AttributeValueLengthLimit , a )
2022-02-07 22:58:05 +02:00
s . attributes = append ( s . attributes , a )
exists [ a . Key ] = len ( s . attributes ) - 1
}
}
2019-08-02 22:52:55 +02:00
}
2022-03-03 17:56:07 +02:00
// truncateAttr returns a truncated version of attr. Only string and string
// slice attribute values are truncated. String values are truncated to at
2022-09-12 16:54:58 +02:00
// most a length of limit. Each string slice value is truncated in this fashion
2022-03-03 17:56:07 +02:00
// (the slice length itself is unaffected).
//
2023-04-12 02:28:13 +02:00
// No truncation is performed for a negative limit.
2022-03-03 17:56:07 +02:00
func truncateAttr ( limit int , attr attribute . KeyValue ) attribute . KeyValue {
if limit < 0 {
return attr
}
switch attr . Value . Type ( ) {
case attribute . STRING :
if v := attr . Value . AsString ( ) ; len ( v ) > limit {
2022-09-12 16:54:58 +02:00
return attr . Key . String ( safeTruncate ( v , limit ) )
2022-03-03 17:56:07 +02:00
}
case attribute . STRINGSLICE :
2022-10-13 16:34:02 +02:00
v := attr . Value . AsStringSlice ( )
2022-03-03 17:56:07 +02:00
for i := range v {
if len ( v [ i ] ) > limit {
2022-09-12 16:54:58 +02:00
v [ i ] = safeTruncate ( v [ i ] , limit )
2022-03-03 17:56:07 +02:00
}
}
2022-10-13 16:34:02 +02:00
return attr . Key . StringSlice ( v )
2022-03-03 17:56:07 +02:00
}
return attr
}
2022-09-12 16:54:58 +02:00
// safeTruncate truncates the string and guarantees valid UTF-8 is returned.
func safeTruncate ( input string , limit int ) string {
if trunc , ok := safeTruncateValidUTF8 ( input , limit ) ; ok {
return trunc
}
trunc , _ := safeTruncateValidUTF8 ( strings . ToValidUTF8 ( input , "" ) , limit )
return trunc
}
// safeTruncateValidUTF8 returns a copy of the input string safely truncated to
// limit. The truncation is ensured to occur at the bounds of complete UTF-8
// characters. If invalid encoding of UTF-8 is encountered, input is returned
// with false, otherwise, the truncated input will be returned with true.
func safeTruncateValidUTF8 ( input string , limit int ) ( string , bool ) {
for cnt := 0 ; cnt <= limit ; {
r , size := utf8 . DecodeRuneInString ( input [ cnt : ] )
if r == utf8 . RuneError {
return input , false
}
if cnt + size > limit {
return input [ : cnt ] , true
}
cnt += size
}
return input , true
}
2021-02-17 16:41:18 +02:00
// End ends the span. This method does nothing if the span is already ended or
// is not being recorded.
2020-09-03 16:34:36 +02:00
//
// The only SpanOption currently supported is WithTimestamp which will set the
// end time for a Span's life-cycle.
//
// If this method is called while panicking an error event is added to the
// Span before ending it and the panic is continued.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) End ( options ... trace . SpanEndOption ) {
2021-02-17 16:41:18 +02:00
// Do not start by checking if the span is being recorded which requires
// acquiring a lock. Make a minimal check that the span is not nil.
2019-08-02 22:52:55 +02:00
if s == nil {
return
}
2020-12-11 07:15:44 +02:00
// Store the end time as soon as possible to avoid artificially increasing
// the span's duration in case some operation below takes a while.
2024-05-31 12:37:38 +02:00
et := monotonicEndTime ( s . startTime )
2020-12-11 07:15:44 +02:00
2024-10-09 09:51:17 +02:00
// Lock the span now that we have an end time and see if we need to do any more processing.
s . mu . Lock ( )
if ! s . isRecording ( ) {
s . mu . Unlock ( )
2021-02-17 16:41:18 +02:00
return
}
2021-08-13 23:44:18 +02:00
config := trace . NewSpanEndConfig ( options ... )
2020-08-08 21:10:36 +02:00
if recovered := recover ( ) ; recovered != nil {
// Record but don't stop the panic.
defer panic ( recovered )
2021-08-13 23:44:18 +02:00
opts := [ ] trace . EventOption {
2020-11-07 00:13:31 +02:00
trace . WithAttributes (
2023-02-07 23:42:47 +02:00
semconv . ExceptionType ( typeStr ( recovered ) ) ,
semconv . ExceptionMessage ( fmt . Sprint ( recovered ) ) ,
2020-10-16 17:09:27 +02:00
) ,
2021-08-13 23:44:18 +02:00
}
if config . StackTrace ( ) {
opts = append ( opts , trace . WithAttributes (
2023-02-07 23:42:47 +02:00
semconv . ExceptionStacktrace ( recordStackTrace ( ) ) ,
2021-08-13 23:44:18 +02:00
) )
}
s . addEvent ( semconv . ExceptionEventName , opts ... )
2020-08-08 21:10:36 +02:00
}
2019-08-02 22:52:55 +02:00
if s . executionTracerTaskEnd != nil {
2024-10-09 09:51:17 +02:00
s . mu . Unlock ( )
2019-08-02 22:52:55 +02:00
s . executionTracerTaskEnd ( )
2024-10-09 09:51:17 +02:00
s . mu . Lock ( )
2019-08-02 22:52:55 +02:00
}
2020-12-11 07:15:44 +02:00
2021-02-17 16:41:18 +02:00
// Setting endTime to non-zero marks the span as ended and not recording.
2021-05-27 16:53:56 +02:00
if config . Timestamp ( ) . IsZero ( ) {
2020-12-11 07:15:44 +02:00
s . endTime = et
} else {
2021-05-27 16:53:56 +02:00
s . endTime = config . Timestamp ( )
2020-12-11 07:15:44 +02:00
}
s . mu . Unlock ( )
2023-04-01 16:57:35 +02:00
sps := s . tracer . provider . getSpanProcessors ( )
2022-10-12 22:44:18 +02:00
if len ( sps ) == 0 {
return
}
snap := s . snapshot ( )
for _ , sp := range sps {
sp . sp . OnEnd ( snap )
2020-12-11 07:15:44 +02:00
}
2019-08-02 22:52:55 +02:00
}
2024-05-31 12:37:38 +02:00
// monotonicEndTime returns the end time at present but offset from start,
// monotonically.
//
// The monotonic clock is used in subtractions hence the duration since start
// added back to start gives end as a monotonic time. See
// https://golang.org/pkg/time/#hdr-Monotonic_Clocks
func monotonicEndTime ( start time . Time ) time . Time {
return start . Add ( time . Since ( start ) )
}
2021-03-08 21:31:01 +02:00
// RecordError will record err as a span event for this span. An additional call to
// SetStatus is required if the Status of the Span should be set to Error, this method
// does not change the Span status. If this span is not being recorded or err is nil
// than this method does nothing.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) RecordError ( err error , opts ... trace . EventOption ) {
2024-10-09 09:51:17 +02:00
if s == nil || err == nil {
return
}
s . mu . Lock ( )
defer s . mu . Unlock ( )
if ! s . isRecording ( ) {
2020-02-28 23:44:53 +02:00
return
}
2020-11-07 00:13:31 +02:00
opts = append ( opts , trace . WithAttributes (
2023-02-07 23:42:47 +02:00
semconv . ExceptionType ( typeStr ( err ) ) ,
semconv . ExceptionMessage ( err . Error ( ) ) ,
2020-10-16 17:09:27 +02:00
) )
2021-08-13 23:44:18 +02:00
c := trace . NewEventConfig ( opts ... )
if c . StackTrace ( ) {
opts = append ( opts , trace . WithAttributes (
2023-02-07 23:42:47 +02:00
semconv . ExceptionStacktrace ( recordStackTrace ( ) ) ,
2021-08-13 23:44:18 +02:00
) )
}
2021-04-01 22:07:46 +02:00
s . addEvent ( semconv . ExceptionEventName , opts ... )
2020-02-28 23:44:53 +02:00
}
2020-08-08 21:10:36 +02:00
func typeStr ( i interface { } ) string {
t := reflect . TypeOf ( i )
if t . PkgPath ( ) == "" && t . Name ( ) == "" {
// Likely a builtin type.
return t . String ( )
}
return fmt . Sprintf ( "%s.%s" , t . PkgPath ( ) , t . Name ( ) )
}
2021-08-13 23:44:18 +02:00
func recordStackTrace ( ) string {
stackTrace := make ( [ ] byte , 2048 )
n := runtime . Stack ( stackTrace , false )
return string ( stackTrace [ 0 : n ] )
}
2021-02-17 16:41:18 +02:00
// AddEvent adds an event with the provided name and options. If this span is
2024-10-09 09:51:17 +02:00
// not being recorded then this method does nothing.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) AddEvent ( name string , o ... trace . EventOption ) {
2024-10-09 09:51:17 +02:00
if s == nil {
return
}
s . mu . Lock ( )
defer s . mu . Unlock ( )
if ! s . isRecording ( ) {
2019-08-02 22:52:55 +02:00
return
}
2020-10-16 17:09:27 +02:00
s . addEvent ( name , o ... )
2019-08-02 22:52:55 +02:00
}
2024-10-09 09:51:17 +02:00
// addEvent adds an event with the provided name and options.
//
// This method assumes s.mu.Lock is held by the caller.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) addEvent ( name string , o ... trace . EventOption ) {
2020-11-07 00:13:31 +02:00
c := trace . NewEventConfig ( o ... )
2022-03-03 17:56:07 +02:00
e := Event { Name : name , Attributes : c . Attributes ( ) , Time : c . Timestamp ( ) }
// Discard attributes over limit.
limit := s . tracer . provider . spanLimits . AttributePerEventCountLimit
if limit == 0 {
// Drop all attributes.
e . DroppedAttributeCount = len ( e . Attributes )
e . Attributes = nil
} else if limit > 0 && len ( e . Attributes ) > limit {
// Drop over capacity.
e . DroppedAttributeCount = len ( e . Attributes ) - limit
e . Attributes = e . Attributes [ : limit ]
2021-02-18 21:31:35 +02:00
}
2022-03-03 17:56:07 +02:00
s . events . add ( e )
2019-08-02 22:52:55 +02:00
}
2021-02-17 16:41:18 +02:00
// SetName sets the name of this span. If this span is not being recorded than
// this method does nothing.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) SetName ( name string ) {
2024-10-07 09:30:29 +02:00
if s == nil {
2021-02-17 16:41:18 +02:00
return
}
2019-10-23 00:25:33 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
2024-10-07 09:30:29 +02:00
if ! s . isRecording ( ) {
return
}
2020-12-11 07:15:44 +02:00
s . name = name
2019-08-26 20:53:12 +02:00
}
2021-02-17 16:41:18 +02:00
// Name returns the name of this span.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) Name ( ) string {
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
return s . name
}
2021-02-17 16:41:18 +02:00
// Name returns the SpanContext of this span's parent span.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) Parent ( ) trace . SpanContext {
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
return s . parent
}
2021-02-17 16:41:18 +02:00
// SpanKind returns the SpanKind of this span.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) SpanKind ( ) trace . SpanKind {
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
return s . spanKind
}
2021-02-17 16:41:18 +02:00
// StartTime returns the time this span started.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) StartTime ( ) time . Time {
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
return s . startTime
}
2021-02-17 16:41:18 +02:00
// EndTime returns the time this span ended. For spans that have not yet
// ended, the returned value will be the zero value of time.Time.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) EndTime ( ) time . Time {
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
return s . endTime
}
2021-02-17 16:41:18 +02:00
// Attributes returns the attributes of this span.
2022-02-07 22:58:05 +02:00
//
// The order of the returned attributes is not guaranteed to be stable.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) Attributes ( ) [ ] attribute . KeyValue {
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
2022-02-07 22:58:05 +02:00
s . dedupeAttrs ( )
return s . attributes
}
// dedupeAttrs deduplicates the attributes of s to fit capacity.
//
// This method assumes s.mu.Lock is held by the caller.
func ( s * recordingSpan ) dedupeAttrs ( ) {
// Do not set a capacity when creating this map. Benchmark testing has
// showed this to only add unused memory allocations in general use.
2024-10-07 09:30:29 +02:00
exists := make ( map [ attribute . Key ] int , len ( s . attributes ) )
s . dedupeAttrsFromRecord ( exists )
2022-02-07 22:58:05 +02:00
}
// dedupeAttrsFromRecord deduplicates the attributes of s to fit capacity
// using record as the record of unique attribute keys to their index.
//
// This method assumes s.mu.Lock is held by the caller.
2024-10-07 09:30:29 +02:00
func ( s * recordingSpan ) dedupeAttrsFromRecord ( record map [ attribute . Key ] int ) {
2022-02-07 22:58:05 +02:00
// Use the fact that slices share the same backing array.
unique := s . attributes [ : 0 ]
for _ , a := range s . attributes {
2024-10-07 09:30:29 +02:00
if idx , ok := record [ a . Key ] ; ok {
2022-02-07 22:58:05 +02:00
unique [ idx ] = a
} else {
unique = append ( unique , a )
2024-10-07 09:30:29 +02:00
record [ a . Key ] = len ( unique ) - 1
2022-02-07 22:58:05 +02:00
}
2020-12-11 07:15:44 +02:00
}
2022-02-07 22:58:05 +02:00
// s.attributes have element types of attribute.KeyValue. These types are
// not pointers and they themselves do not contain pointer fields,
// therefore the duplicate values do not need to be zeroed for them to be
// garbage collected.
s . attributes = unique
2020-12-11 07:15:44 +02:00
}
2021-04-23 17:04:59 +02:00
// Links returns the links of this span.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) Links ( ) [ ] Link {
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
if len ( s . links . queue ) == 0 {
2021-07-26 17:06:41 +02:00
return [ ] Link { }
2020-12-11 07:15:44 +02:00
}
2024-05-30 20:40:08 +02:00
return s . links . copy ( )
2020-12-11 07:15:44 +02:00
}
2021-02-17 16:41:18 +02:00
// Events returns the events of this span.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) Events ( ) [ ] Event {
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
2021-05-05 01:45:13 +02:00
if len ( s . events . queue ) == 0 {
2021-04-29 19:29:48 +02:00
return [ ] Event { }
2020-12-11 07:15:44 +02:00
}
2024-05-30 20:40:08 +02:00
return s . events . copy ( )
2020-12-11 07:15:44 +02:00
}
2021-05-03 21:00:54 +02:00
// Status returns the status of this span.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) Status ( ) Status {
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
2021-05-03 21:00:54 +02:00
return s . status
2020-12-11 07:15:44 +02:00
}
2022-07-06 20:55:46 +02:00
// InstrumentationScope returns the instrumentation.Scope associated with
// the Tracer that created this span.
func ( s * recordingSpan ) InstrumentationScope ( ) instrumentation . Scope {
s . mu . Lock ( )
defer s . mu . Unlock ( )
return s . tracer . instrumentationScope
}
2021-02-17 16:41:18 +02:00
// InstrumentationLibrary returns the instrumentation.Library associated with
// the Tracer that created this span.
2024-07-24 09:33:07 +02:00
func ( s * recordingSpan ) InstrumentationLibrary ( ) instrumentation . Library { //nolint:staticcheck // This method needs to be define for backwards compatibility
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
2022-07-06 20:55:46 +02:00
return s . tracer . instrumentationScope
2020-12-11 07:15:44 +02:00
}
2021-02-17 16:41:18 +02:00
// Resource returns the Resource associated with the Tracer that created this
// span.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) Resource ( ) * resource . Resource {
2020-12-11 07:15:44 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
2022-02-02 01:20:35 +02:00
return s . tracer . provider . resource
2020-12-11 07:15:44 +02:00
}
2024-03-28 09:35:15 +02:00
func ( s * recordingSpan ) AddLink ( link trace . Link ) {
2024-10-09 09:51:17 +02:00
if s == nil {
2024-05-09 22:25:02 +02:00
return
}
if ! link . SpanContext . IsValid ( ) && len ( link . Attributes ) == 0 &&
link . SpanContext . TraceState ( ) . Len ( ) == 0 {
2019-09-21 09:26:20 +02:00
return
}
2021-07-26 17:06:41 +02:00
2024-10-09 09:51:17 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
if ! s . isRecording ( ) {
return
}
2022-03-03 17:56:07 +02:00
l := Link { SpanContext : link . SpanContext , Attributes : link . Attributes }
// Discard attributes over limit.
limit := s . tracer . provider . spanLimits . AttributePerLinkCountLimit
if limit == 0 {
// Drop all attributes.
l . DroppedAttributeCount = len ( l . Attributes )
l . Attributes = nil
} else if limit > 0 && len ( l . Attributes ) > limit {
l . DroppedAttributeCount = len ( l . Attributes ) - limit
l . Attributes = l . Attributes [ : limit ]
2021-02-18 21:31:35 +02:00
}
2022-03-03 17:56:07 +02:00
s . links . add ( l )
2019-09-21 09:26:20 +02:00
}
2021-05-05 01:45:13 +02:00
// DroppedAttributes returns the number of attributes dropped by the span
// due to limits being reached.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) DroppedAttributes ( ) int {
2019-08-02 22:52:55 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
2022-02-07 22:58:05 +02:00
return s . droppedAttributes
2021-05-05 01:45:13 +02:00
}
// DroppedLinks returns the number of links dropped by the span due to limits
// being reached.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) DroppedLinks ( ) int {
2021-05-05 01:45:13 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
return s . links . droppedCount
}
2019-11-18 20:51:57 +02:00
2021-05-05 01:45:13 +02:00
// DroppedEvents returns the number of events dropped by the span due to
// limits being reached.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) DroppedEvents ( ) int {
2021-05-05 01:45:13 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
return s . events . droppedCount
}
// ChildSpanCount returns the count of spans that consider the span a
// direct parent.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) ChildSpanCount ( ) int {
2021-05-05 01:45:13 +02:00
s . mu . Lock ( )
defer s . mu . Unlock ( )
return s . childSpanCount
}
2021-06-17 18:05:44 +02:00
// TracerProvider returns a trace.TracerProvider that can be used to generate
// additional Spans on the same telemetry pipeline as the current Span.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) TracerProvider ( ) trace . TracerProvider {
2021-06-17 18:05:44 +02:00
return s . tracer . provider
}
2021-05-05 01:45:13 +02:00
// snapshot creates a read-only copy of the current state of the span.
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) snapshot ( ) ReadOnlySpan {
2021-05-05 01:45:13 +02:00
var sd snapshot
s . mu . Lock ( )
defer s . mu . Unlock ( )
sd . endTime = s . endTime
2022-07-06 20:55:46 +02:00
sd . instrumentationScope = s . tracer . instrumentationScope
2021-05-05 01:45:13 +02:00
sd . name = s . name
sd . parent = s . parent
2022-02-02 01:20:35 +02:00
sd . resource = s . tracer . provider . resource
2021-05-05 01:45:13 +02:00
sd . spanContext = s . spanContext
sd . spanKind = s . spanKind
sd . startTime = s . startTime
sd . status = s . status
sd . childSpanCount = s . childSpanCount
2020-12-11 07:15:44 +02:00
2022-02-07 22:58:05 +02:00
if len ( s . attributes ) > 0 {
s . dedupeAttrs ( )
sd . attributes = s . attributes
2020-12-11 07:15:44 +02:00
}
2022-02-07 22:58:05 +02:00
sd . droppedAttributeCount = s . droppedAttributes
2021-05-05 01:45:13 +02:00
if len ( s . events . queue ) > 0 {
2024-05-30 20:40:08 +02:00
sd . events = s . events . copy ( )
2021-05-05 01:45:13 +02:00
sd . droppedEventCount = s . events . droppedCount
2019-08-02 22:52:55 +02:00
}
2019-09-21 09:26:20 +02:00
if len ( s . links . queue ) > 0 {
2024-05-30 20:40:08 +02:00
sd . links = s . links . copy ( )
2021-05-05 01:45:13 +02:00
sd . droppedLinkCount = s . links . droppedCount
2019-09-21 09:26:20 +02:00
}
2019-08-02 22:52:55 +02:00
return & sd
}
2021-09-02 23:30:12 +02:00
func ( s * recordingSpan ) addChild ( ) {
2024-10-07 09:30:29 +02:00
if s == nil {
2019-08-02 22:52:55 +02:00
return
}
2024-10-07 09:30:29 +02:00
2019-08-02 22:52:55 +02:00
s . mu . Lock ( )
2024-10-07 09:30:29 +02:00
defer s . mu . Unlock ( )
if ! s . isRecording ( ) {
return
}
2020-12-11 07:15:44 +02:00
s . childSpanCount ++
2019-08-02 22:52:55 +02:00
}
2021-09-02 23:30:12 +02:00
func ( * recordingSpan ) private ( ) { }
2021-02-24 20:03:35 +02:00
2021-09-02 23:30:12 +02:00
// runtimeTrace starts a "runtime/trace".Task for the span and returns a
// context containing the task.
func ( s * recordingSpan ) runtimeTrace ( ctx context . Context ) context . Context {
if ! rt . IsEnabled ( ) {
// Avoid additional overhead if runtime/trace is not enabled.
return ctx
}
nctx , task := rt . NewTask ( ctx , s . name )
2019-08-02 22:52:55 +02:00
2021-09-02 23:30:12 +02:00
s . mu . Lock ( )
s . executionTracerTaskEnd = task . End
s . mu . Unlock ( )
2019-08-02 22:52:55 +02:00
2021-09-02 23:30:12 +02:00
return nctx
}
2021-03-25 16:36:39 +02:00
2021-09-02 23:30:12 +02:00
// nonRecordingSpan is a minimal implementation of the OpenTelemetry Span API
// that wraps a SpanContext. It performs no operations other than to return
// the wrapped SpanContext or TracerProvider that created it.
type nonRecordingSpan struct {
2023-10-19 19:16:24 +02:00
embedded . Span
2021-09-02 23:30:12 +02:00
// tracer is the SDK tracer that created this span.
tracer * tracer
sc trace . SpanContext
}
2020-12-11 07:15:44 +02:00
2021-09-02 23:30:12 +02:00
var _ trace . Span = nonRecordingSpan { }
2021-03-25 16:36:39 +02:00
2021-09-02 23:30:12 +02:00
// SpanContext returns the wrapped SpanContext.
func ( s nonRecordingSpan ) SpanContext ( ) trace . SpanContext { return s . sc }
2019-08-02 22:52:55 +02:00
2021-09-02 23:30:12 +02:00
// IsRecording always returns false.
func ( nonRecordingSpan ) IsRecording ( ) bool { return false }
2019-08-02 22:52:55 +02:00
2021-09-02 23:30:12 +02:00
// SetStatus does nothing.
func ( nonRecordingSpan ) SetStatus ( codes . Code , string ) { }
2020-12-11 07:15:44 +02:00
2021-09-02 23:30:12 +02:00
// SetError does nothing.
func ( nonRecordingSpan ) SetError ( bool ) { }
2019-08-02 22:52:55 +02:00
2021-09-02 23:30:12 +02:00
// SetAttributes does nothing.
func ( nonRecordingSpan ) SetAttributes ( ... attribute . KeyValue ) { }
2020-03-10 17:25:11 +02:00
2021-09-02 23:30:12 +02:00
// End does nothing.
func ( nonRecordingSpan ) End ( ... trace . SpanEndOption ) { }
// RecordError does nothing.
func ( nonRecordingSpan ) RecordError ( error , ... trace . EventOption ) { }
// AddEvent does nothing.
func ( nonRecordingSpan ) AddEvent ( string , ... trace . EventOption ) { }
2024-03-28 09:35:15 +02:00
// AddLink does nothing.
func ( nonRecordingSpan ) AddLink ( trace . Link ) { }
2021-09-02 23:30:12 +02:00
// SetName does nothing.
func ( nonRecordingSpan ) SetName ( string ) { }
// TracerProvider returns the trace.TracerProvider that provided the Tracer
// that created this span.
func ( s nonRecordingSpan ) TracerProvider ( ) trace . TracerProvider { return s . tracer . provider }
2019-08-26 20:53:12 +02:00
2021-03-09 19:45:09 +02:00
func isRecording ( s SamplingResult ) bool {
return s . Decision == RecordOnly || s . Decision == RecordAndSample
}
func isSampled ( s SamplingResult ) bool {
return s . Decision == RecordAndSample
2019-08-26 20:53:12 +02:00
}
2021-04-07 17:03:43 +02:00
2021-05-03 21:00:54 +02:00
// Status is the classified state of a Span.
type Status struct {
2021-05-05 01:45:13 +02:00
// Code is an identifier of a Spans state classification.
2021-05-03 21:00:54 +02:00
Code codes . Code
2021-06-24 21:41:08 +02:00
// Description is a user hint about why that status was set. It is only
2021-05-03 21:00:54 +02:00
// applicable when Code is Error.
Description string
}