summaryrefslogtreecommitdiff
path: root/vendor/go.opentelemetry.io/otel/sdk/trace
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.opentelemetry.io/otel/sdk/trace')
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/batch_span_processor.go7
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/evictedqueue.go21
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/provider.go9
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/sampler_env.go5
-rw-r--r--vendor/go.opentelemetry.io/otel/sdk/trace/span.go209
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() {}