diff options
Diffstat (limited to 'vendor/go.opentelemetry.io/otel/sdk/trace')
5 files changed, 176 insertions, 75 deletions
| diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go b/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go index 1d399a75d..ccc97e1b6 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go @@ -280,6 +280,7 @@ func (bsp *batchSpanProcessor) exportSpans(ctx context.Context) error {  		//  		// It is up to the exporter to implement any type of retry logic if a batch is failing  		// to be exported, since it is specific to the protocol and backend being sent to. +		clear(bsp.batch) // Erase elements to let GC collect objects  		bsp.batch = bsp.batch[:0]  		if err != nil { @@ -316,7 +317,11 @@ func (bsp *batchSpanProcessor) processQueue() {  			bsp.batchMutex.Unlock()  			if shouldExport {  				if !bsp.timer.Stop() { -					<-bsp.timer.C +					// Handle both GODEBUG=asynctimerchan=[0|1] properly. +					select { +					case <-bsp.timer.C: +					default: +					}  				}  				if err := bsp.exportSpans(ctx); err != nil {  					otel.Handle(err) diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go b/vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go index 821c83faa..8c308dd60 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go @@ -12,25 +12,26 @@ import (  // evictedQueue is a FIFO queue with a configurable capacity.  type evictedQueue[T any] struct { -	queue        []T -	capacity     int -	droppedCount int -	logDropped   func() +	queue          []T +	capacity       int +	droppedCount   int +	logDroppedMsg  string +	logDroppedOnce sync.Once  }  func newEvictedQueueEvent(capacity int) evictedQueue[Event] {  	// Do not pre-allocate queue, do this lazily.  	return evictedQueue[Event]{ -		capacity:   capacity, -		logDropped: sync.OnceFunc(func() { global.Warn("limit reached: dropping trace trace.Event") }), +		capacity:      capacity, +		logDroppedMsg: "limit reached: dropping trace trace.Event",  	}  }  func newEvictedQueueLink(capacity int) evictedQueue[Link] {  	// Do not pre-allocate queue, do this lazily.  	return evictedQueue[Link]{ -		capacity:   capacity, -		logDropped: sync.OnceFunc(func() { global.Warn("limit reached: dropping trace trace.Link") }), +		capacity:      capacity, +		logDroppedMsg: "limit reached: dropping trace trace.Link",  	}  } @@ -53,6 +54,10 @@ func (eq *evictedQueue[T]) add(value T) {  	eq.queue = append(eq.queue, value)  } +func (eq *evictedQueue[T]) logDropped() { +	eq.logDroppedOnce.Do(func() { global.Warn(eq.logDroppedMsg) }) +} +  // copy returns a copy of the evictedQueue.  func (eq *evictedQueue[T]) copy() []T {  	return slices.Clone(eq.queue) diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go b/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go index 14c2e5beb..185aa7c08 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/provider.go @@ -139,9 +139,10 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T  		name = defaultTracerName  	}  	is := instrumentation.Scope{ -		Name:      name, -		Version:   c.InstrumentationVersion(), -		SchemaURL: c.SchemaURL(), +		Name:       name, +		Version:    c.InstrumentationVersion(), +		SchemaURL:  c.SchemaURL(), +		Attributes: c.InstrumentationAttributes(),  	}  	t, ok := func() (trace.Tracer, bool) { @@ -168,7 +169,7 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T  		//   slowing down all tracing consumers.  		// - Logging code may be instrumented with tracing and deadlock because it could try  		//   acquiring the same non-reentrant mutex. -		global.Info("Tracer created", "name", name, "version", is.Version, "schemaURL", is.SchemaURL) +		global.Info("Tracer created", "name", name, "version", is.Version, "schemaURL", is.SchemaURL, "attributes", is.Attributes)  	}  	return t  } diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go b/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go index d2d1f7246..9b672a1d7 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go @@ -5,7 +5,6 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace"  import (  	"errors" -	"fmt"  	"os"  	"strconv"  	"strings" @@ -26,7 +25,7 @@ const (  type errUnsupportedSampler string  func (e errUnsupportedSampler) Error() string { -	return fmt.Sprintf("unsupported sampler: %s", string(e)) +	return "unsupported sampler: " + string(e)  }  var ( @@ -39,7 +38,7 @@ type samplerArgParseError struct {  }  func (e samplerArgParseError) Error() string { -	return fmt.Sprintf("parsing sampler argument: %s", e.parseErr.Error()) +	return "parsing sampler argument: " + e.parseErr.Error()  }  func (e samplerArgParseError) Unwrap() error { diff --git a/vendor/go.opentelemetry.io/otel/sdk/trace/span.go b/vendor/go.opentelemetry.io/otel/sdk/trace/span.go index 4945f5083..8f4fc3850 100644 --- a/vendor/go.opentelemetry.io/otel/sdk/trace/span.go +++ b/vendor/go.opentelemetry.io/otel/sdk/trace/span.go @@ -174,6 +174,17 @@ func (s *recordingSpan) IsRecording() bool {  	s.mu.Lock()  	defer s.mu.Unlock() +	return s.isRecording() +} + +// isRecording returns if this span is being recorded. If this span has ended +// this will return false. +// +// This method assumes s.mu.Lock is held by the caller. +func (s *recordingSpan) isRecording() bool { +	if s == nil { +		return false +	}  	return s.endTime.IsZero()  } @@ -182,11 +193,15 @@ func (s *recordingSpan) IsRecording() bool {  // included in the set status when the code is for an error. If this span is  // not being recorded than this method does nothing.  func (s *recordingSpan) SetStatus(code codes.Code, description string) { -	if !s.IsRecording() { +	if s == nil {  		return  	} +  	s.mu.Lock()  	defer s.mu.Unlock() +	if !s.isRecording() { +		return +	}  	if s.status.Code > code {  		return  	} @@ -210,12 +225,15 @@ func (s *recordingSpan) SetStatus(code codes.Code, description string) {  // attributes the span is configured to have, the last added attributes will  // be dropped.  func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) { -	if !s.IsRecording() { +	if s == nil || len(attributes) == 0 {  		return  	}  	s.mu.Lock()  	defer s.mu.Unlock() +	if !s.isRecording() { +		return +	}  	limit := s.tracer.provider.spanLimits.AttributeCountLimit  	if limit == 0 { @@ -233,7 +251,7 @@ func (s *recordingSpan) SetAttributes(attributes ...attribute.KeyValue) {  	// Otherwise, add without deduplication. When attributes are read they  	// will be deduplicated, optimizing the operation. -	s.attributes = slices.Grow(s.attributes, len(s.attributes)+len(attributes)) +	s.attributes = slices.Grow(s.attributes, len(attributes))  	for _, a := range attributes {  		if !a.Valid() {  			// Drop all invalid attributes. @@ -280,13 +298,17 @@ func (s *recordingSpan) addOverCapAttrs(limit int, attrs []attribute.KeyValue) {  	// Do not set a capacity when creating this map. Benchmark testing has  	// showed this to only add unused memory allocations in general use. -	exists := make(map[attribute.Key]int) -	s.dedupeAttrsFromRecord(&exists) +	exists := make(map[attribute.Key]int, len(s.attributes)) +	s.dedupeAttrsFromRecord(exists)  	// Now that s.attributes is deduplicated, adding unique attributes up to  	// the capacity of s will not over allocate s.attributes. -	sum := len(attrs) + len(s.attributes) -	s.attributes = slices.Grow(s.attributes, min(sum, limit)) + +	// 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)) +	}  	for _, a := range attrs {  		if !a.Valid() {  			// Drop all invalid attributes. @@ -296,6 +318,7 @@ func (s *recordingSpan) addOverCapAttrs(limit int, attrs []attribute.KeyValue) {  		if idx, ok := exists[a.Key]; ok {  			// Perform all updates before dropping, even when at capacity. +			a = truncateAttr(s.tracer.provider.spanLimits.AttributeValueLengthLimit, a)  			s.attributes[idx] = a  			continue  		} @@ -324,54 +347,99 @@ func truncateAttr(limit int, attr attribute.KeyValue) attribute.KeyValue {  	}  	switch attr.Value.Type() {  	case attribute.STRING: -		if v := attr.Value.AsString(); len(v) > limit { -			return attr.Key.String(safeTruncate(v, limit)) -		} +		v := attr.Value.AsString() +		return attr.Key.String(truncate(limit, v))  	case attribute.STRINGSLICE:  		v := attr.Value.AsStringSlice()  		for i := range v { -			if len(v[i]) > limit { -				v[i] = safeTruncate(v[i], limit) -			} +			v[i] = truncate(limit, v[i])  		}  		return attr.Key.StringSlice(v)  	}  	return attr  } -// 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 +// truncate returns a truncated version of s such that it contains less than +// the limit number of characters. Truncation is applied by returning the limit +// number of valid characters contained in s. +// +// If limit is negative, it returns the original string. +// +// UTF-8 is supported. When truncating, all invalid characters are dropped +// before applying truncation. +// +// If s already contains less than the limit number of bytes, it is returned +// unchanged. No invalid characters are removed. +func truncate(limit int, s string) string { +	// This prioritize performance in the following order based on the most +	// common expected use-cases. +	// +	//  - Short values less than the default limit (128). +	//  - Strings with valid encodings that exceed the limit. +	//  - No limit. +	//  - Strings with invalid encodings that exceed the limit. +	if limit < 0 || len(s) <= limit { +		return s +	} + +	// Optimistically, assume all valid UTF-8. +	var b strings.Builder +	count := 0 +	for i, c := range s { +		if c != utf8.RuneError { +			count++ +			if count > limit { +				return s[:i] +			} +			continue +		} + +		_, size := utf8.DecodeRuneInString(s[i:]) +		if size == 1 { +			// Invalid encoding. +			b.Grow(len(s) - 1) +			_, _ = b.WriteString(s[:i]) +			s = s[i:] +			break +		} +	} + +	// Fast-path, no invalid input. +	if b.Cap() == 0 { +		return s  	} -	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 +	// Truncate while validating UTF-8. +	for i := 0; i < len(s) && count < limit; { +		c := s[i] +		if c < utf8.RuneSelf { +			// Optimization for single byte runes (common case). +			_ = b.WriteByte(c) +			i++ +			count++ +			continue  		} -		if cnt+size > limit { -			return input[:cnt], true +		_, size := utf8.DecodeRuneInString(s[i:]) +		if size == 1 { +			// We checked for all 1-byte runes above, this is a RuneError. +			i++ +			continue  		} -		cnt += size + +		_, _ = b.WriteString(s[i : i+size]) +		i += size +		count++  	} -	return input, true + +	return b.String()  }  // End ends the span. This method does nothing if the span is already ended or  // is not being recorded.  // -// The only SpanOption currently supported is WithTimestamp which will set the -// end time for a Span's life-cycle. +// The only SpanEndOption currently supported are [trace.WithTimestamp], and +// [trace.WithStackTrace].  //  // If this method is called while panicking an error event is added to the  // Span before ending it and the panic is continued. @@ -386,9 +454,10 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {  	// the span's duration in case some operation below takes a while.  	et := monotonicEndTime(s.startTime) -	// Do relative expensive check now that we have an end time and see if we -	// need to do any more processing. -	if !s.IsRecording() { +	// 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()  		return  	} @@ -413,10 +482,11 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {  	}  	if s.executionTracerTaskEnd != nil { +		s.mu.Unlock()  		s.executionTracerTaskEnd() +		s.mu.Lock()  	} -	s.mu.Lock()  	// Setting endTime to non-zero marks the span as ended and not recording.  	if config.Timestamp().IsZero() {  		s.endTime = et @@ -450,7 +520,13 @@ func monotonicEndTime(start time.Time) time.Time {  // does not change the Span status. If this span is not being recorded or err is nil  // than this method does nothing.  func (s *recordingSpan) RecordError(err error, opts ...trace.EventOption) { -	if s == nil || err == nil || !s.IsRecording() { +	if s == nil || err == nil { +		return +	} + +	s.mu.Lock() +	defer s.mu.Unlock() +	if !s.isRecording() {  		return  	} @@ -486,14 +562,23 @@ func recordStackTrace() string {  }  // AddEvent adds an event with the provided name and options. If this span is -// not being recorded than this method does nothing. +// not being recorded then this method does nothing.  func (s *recordingSpan) AddEvent(name string, o ...trace.EventOption) { -	if !s.IsRecording() { +	if s == nil { +		return +	} + +	s.mu.Lock() +	defer s.mu.Unlock() +	if !s.isRecording() {  		return  	}  	s.addEvent(name, o...)  } +// addEvent adds an event with the provided name and options. +// +// This method assumes s.mu.Lock is held by the caller.  func (s *recordingSpan) addEvent(name string, o ...trace.EventOption) {  	c := trace.NewEventConfig(o...)  	e := Event{Name: name, Attributes: c.Attributes(), Time: c.Timestamp()} @@ -510,20 +595,21 @@ func (s *recordingSpan) addEvent(name string, o ...trace.EventOption) {  		e.Attributes = e.Attributes[:limit]  	} -	s.mu.Lock()  	s.events.add(e) -	s.mu.Unlock()  }  // SetName sets the name of this span. If this span is not being recorded than  // this method does nothing.  func (s *recordingSpan) SetName(name string) { -	if !s.IsRecording() { +	if s == nil {  		return  	}  	s.mu.Lock()  	defer s.mu.Unlock() +	if !s.isRecording() { +		return +	}  	s.name = name  } @@ -579,29 +665,26 @@ func (s *recordingSpan) Attributes() []attribute.KeyValue {  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. -	exists := make(map[attribute.Key]int) -	s.dedupeAttrsFromRecord(&exists) +	exists := make(map[attribute.Key]int, len(s.attributes)) +	s.dedupeAttrsFromRecord(exists)  }  // 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. -func (s *recordingSpan) dedupeAttrsFromRecord(record *map[attribute.Key]int) { +func (s *recordingSpan) dedupeAttrsFromRecord(record map[attribute.Key]int) {  	// Use the fact that slices share the same backing array.  	unique := s.attributes[:0]  	for _, a := range s.attributes { -		if idx, ok := (*record)[a.Key]; ok { +		if idx, ok := record[a.Key]; ok {  			unique[idx] = a  		} else {  			unique = append(unique, a) -			(*record)[a.Key] = len(unique) - 1 +			record[a.Key] = len(unique) - 1  		}  	} -	// 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. +	clear(s.attributes[len(unique):]) // Erase unneeded elements to let GC collect objects.  	s.attributes = unique  } @@ -657,7 +740,7 @@ func (s *recordingSpan) Resource() *resource.Resource {  }  func (s *recordingSpan) AddLink(link trace.Link) { -	if !s.IsRecording() { +	if s == nil {  		return  	}  	if !link.SpanContext.IsValid() && len(link.Attributes) == 0 && @@ -665,6 +748,12 @@ func (s *recordingSpan) AddLink(link trace.Link) {  		return  	} +	s.mu.Lock() +	defer s.mu.Unlock() +	if !s.isRecording() { +		return +	} +  	l := Link{SpanContext: link.SpanContext, Attributes: link.Attributes}  	// Discard attributes over limit. @@ -678,9 +767,7 @@ func (s *recordingSpan) AddLink(link trace.Link) {  		l.Attributes = l.Attributes[:limit]  	} -	s.mu.Lock()  	s.links.add(l) -	s.mu.Unlock()  }  // DroppedAttributes returns the number of attributes dropped by the span @@ -755,12 +842,16 @@ func (s *recordingSpan) snapshot() ReadOnlySpan {  }  func (s *recordingSpan) addChild() { -	if !s.IsRecording() { +	if s == nil {  		return  	} +  	s.mu.Lock() +	defer s.mu.Unlock() +	if !s.isRecording() { +		return +	}  	s.childSpanCount++ -	s.mu.Unlock()  }  func (*recordingSpan) private() {} | 
