Skip to content

Commit 0d0a732

Browse files
MrAliasAneurysm9
andauthored
Update span limits to comply with specification (#2637)
* PoC for span limit refactor * Rename config.go to span_limits.go * Add unit tests for truncateAttr * Add unit tests for non-string attrs * Add span limit benchmark tests * Fix lint * Isolate span limit tests * Clean span limits test * Test limits on exported spans * Remove duplicate test code * Fix lint * Add WithRawSpanLimits option * Add test for raw and orig span limits opts * Add changes to changelog * Add tests for span resource disabled * Test unlimited instead of default limit * Update docs * Add fix to changelog * Fix option docs * Do no mutate attribute * Fix truncateAttr comment * Remake NewSpanLimits to be newEnvSpanLimits Update and unify documentation accordingly. * Update truncateAttr string slice update comment * Update CHANGELOG.md Co-authored-by: Anthony Mirabella <[email protected]> Co-authored-by: Anthony Mirabella <[email protected]>
1 parent 24414b2 commit 0d0a732

12 files changed

+895
-202
lines changed

CHANGELOG.md

+21-2
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,26 @@ This update is a breaking change of the unstable Metrics API. Code instrumented
1414

1515
### Added
1616

17+
- Log the Exporters configuration in the TracerProviders message. (#2578)
1718
- Added support to configure the span limits with environment variables.
18-
The following environment variables are used. (#2606)
19+
The following environment variables are used. (#2606, #2637)
20+
- `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT`
1921
- `OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT`
2022
- `OTEL_SPAN_EVENT_COUNT_LIMIT`
23+
- `OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT`
2124
- `OTEL_SPAN_LINK_COUNT_LIMIT`
25+
- `OTEL_LINK_ATTRIBUTE_COUNT_LIMIT`
2226

2327
If the provided environment variables are invalid (negative), the default values would be used.
2428
- Rename the `gc` runtime name to `go` (#2560)
25-
- Log the Exporters configuration in the TracerProviders message. (#2578)
29+
- Add span attribute value length limit.
30+
The new `AttributeValueLengthLimit` field is added to the `"go.opentelemetry.io/otel/sdk/trace".SpanLimits` type to configure this limit for a `TracerProvider`.
31+
The default limit for this resource is "unlimited". (#2637)
32+
- Add the `WithRawSpanLimits` option to `go.opentelemetry.io/otel/sdk/trace`.
33+
This option replaces the `WithSpanLimits` option.
34+
Zero or negative values will not be changed to the default value like `WithSpanLimits` does.
35+
Setting a limit to zero will effectively disable the related resource it limits and setting to a negative value will mean that resource is unlimited.
36+
Consequentially, limits should be constructed using `NewSpanLimits` and updated accordingly. (#2637)
2637

2738
### Changed
2839

@@ -37,6 +48,14 @@ This update is a breaking change of the unstable Metrics API. Code instrumented
3748

3849
- Remove the OTLP trace exporter limit of SpanEvents when exporting. (#2616)
3950
- Use port `4318` instead of `4317` for default for the `otlpmetrichttp` and `otlptracehttp` client. (#2614, #2625)
51+
- Unlimited span limits are now supported (negative values). (#2636, #2637)
52+
53+
### Deprecated
54+
55+
- Deprecated `"go.opentelemetry.io/otel/sdk/trace".WithSpanLimits`.
56+
Use `WithRawSpanLimits` instead.
57+
That option allows setting unlimited and zero limits, this option does not.
58+
This option will be kept until the next major version incremented release. (#2637)
4059

4160
## [1.4.1] - 2022-02-16
4261

sdk/internal/env/env.go

+56-5
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,29 @@ const (
4141
// i.e. 512
4242
BatchSpanProcessorMaxExportBatchSizeKey = "OTEL_BSP_MAX_EXPORT_BATCH_SIZE"
4343

44-
// SpanAttributesCountKey
44+
// SpanAttributeValueLengthKey
45+
// Maximum allowed attribute value size.
46+
SpanAttributeValueLengthKey = "OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT"
47+
48+
// SpanAttributeCountKey
4549
// Maximum allowed span attribute count
46-
// Default: 128
47-
SpanAttributesCountKey = "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT"
50+
SpanAttributeCountKey = "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT"
4851

4952
// SpanEventCountKey
5053
// Maximum allowed span event count
51-
// Default: 128
5254
SpanEventCountKey = "OTEL_SPAN_EVENT_COUNT_LIMIT"
5355

56+
// SpanEventAttributeCountKey
57+
// Maximum allowed attribute per span event count.
58+
SpanEventAttributeCountKey = "OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT"
59+
5460
// SpanLinkCountKey
5561
// Maximum allowed span link count
56-
// Default: 128
5762
SpanLinkCountKey = "OTEL_SPAN_LINK_COUNT_LIMIT"
63+
64+
// SpanLinkAttributeCountKey
65+
// Maximum allowed attribute per span link count
66+
SpanLinkAttributeCountKey = "OTEL_LINK_ATTRIBUTE_COUNT_LIMIT"
5867
)
5968

6069
// IntEnvOr returns the int value of the environment variable with name key if
@@ -101,3 +110,45 @@ func BatchSpanProcessorMaxQueueSize(defaultValue int) int {
101110
func BatchSpanProcessorMaxExportBatchSize(defaultValue int) int {
102111
return IntEnvOr(BatchSpanProcessorMaxExportBatchSizeKey, defaultValue)
103112
}
113+
114+
// SpanAttributeValueLength returns the environment variable value for the
115+
// OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT key if it exists, otherwise
116+
// defaultValue is returned.
117+
func SpanAttributeValueLength(defaultValue int) int {
118+
return IntEnvOr(SpanAttributeValueLengthKey, defaultValue)
119+
}
120+
121+
// SpanAttributeCount returns the environment variable value for the
122+
// OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT key if it exists, otherwise defaultValue is
123+
// returned.
124+
func SpanAttributeCount(defaultValue int) int {
125+
return IntEnvOr(SpanAttributeCountKey, defaultValue)
126+
}
127+
128+
// SpanEventCount returns the environment variable value for the
129+
// OTEL_SPAN_EVENT_COUNT_LIMIT key if it exists, otherwise defaultValue is
130+
// returned.
131+
func SpanEventCount(defaultValue int) int {
132+
return IntEnvOr(SpanEventCountKey, defaultValue)
133+
}
134+
135+
// SpanEventAttributeCount returns the environment variable value for the
136+
// OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT key if it exists, otherwise defaultValue
137+
// is returned.
138+
func SpanEventAttributeCount(defaultValue int) int {
139+
return IntEnvOr(SpanEventAttributeCountKey, defaultValue)
140+
}
141+
142+
// SpanLinkCount returns the environment variable value for the
143+
// OTEL_SPAN_LINK_COUNT_LIMIT key if it exists, otherwise defaultValue is
144+
// returned.
145+
func SpanLinkCount(defaultValue int) int {
146+
return IntEnvOr(SpanLinkCountKey, defaultValue)
147+
}
148+
149+
// SpanLinkAttributeCount returns the environment variable value for the
150+
// OTEL_LINK_ATTRIBUTE_COUNT_LIMIT key if it exists, otherwise defaultValue is
151+
// returned.
152+
func SpanLinkAttributeCount(defaultValue int) int {
153+
return IntEnvOr(SpanLinkAttributeCountKey, defaultValue)
154+
}

sdk/trace/benchmark_test.go

+99-3
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,106 @@ import (
2525
"go.opentelemetry.io/otel/trace"
2626
)
2727

28+
func benchmarkSpanLimits(b *testing.B, limits sdktrace.SpanLimits) {
29+
tp := sdktrace.NewTracerProvider(sdktrace.WithSpanLimits(limits))
30+
tracer := tp.Tracer(b.Name())
31+
ctx := context.Background()
32+
33+
const count = 8
34+
35+
attrs := []attribute.KeyValue{
36+
attribute.Bool("bool", true),
37+
attribute.BoolSlice("boolSlice", []bool{true, false}),
38+
attribute.Int("int", 42),
39+
attribute.IntSlice("intSlice", []int{42, -1}),
40+
attribute.Int64("int64", 42),
41+
attribute.Int64Slice("int64Slice", []int64{42, -1}),
42+
attribute.Float64("float64", 42),
43+
attribute.Float64Slice("float64Slice", []float64{42, -1}),
44+
attribute.String("string", "value"),
45+
attribute.StringSlice("stringSlice", []string{"value", "value-1"}),
46+
}
47+
48+
links := make([]trace.Link, count)
49+
for i := range links {
50+
links[i] = trace.Link{
51+
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
52+
TraceID: [16]byte{0x01},
53+
SpanID: [8]byte{0x01},
54+
}),
55+
Attributes: attrs,
56+
}
57+
}
58+
59+
events := make([]struct {
60+
name string
61+
attr []attribute.KeyValue
62+
}, count)
63+
for i := range events {
64+
events[i] = struct {
65+
name string
66+
attr []attribute.KeyValue
67+
}{
68+
name: fmt.Sprintf("event-%d", i),
69+
attr: attrs,
70+
}
71+
}
72+
73+
b.ReportAllocs()
74+
b.ResetTimer()
75+
76+
for i := 0; i < b.N; i++ {
77+
_, span := tracer.Start(ctx, "span-name", trace.WithLinks(links...))
78+
span.SetAttributes(attrs...)
79+
for _, e := range events {
80+
span.AddEvent(e.name, trace.WithAttributes(e.attr...))
81+
}
82+
span.End()
83+
}
84+
}
85+
86+
func BenchmarkSpanLimits(b *testing.B) {
87+
b.Run("AttributeValueLengthLimit", func(b *testing.B) {
88+
limits := sdktrace.NewSpanLimits()
89+
limits.AttributeValueLengthLimit = 2
90+
benchmarkSpanLimits(b, limits)
91+
})
92+
93+
b.Run("AttributeCountLimit", func(b *testing.B) {
94+
limits := sdktrace.NewSpanLimits()
95+
limits.AttributeCountLimit = 1
96+
benchmarkSpanLimits(b, limits)
97+
})
98+
99+
b.Run("EventCountLimit", func(b *testing.B) {
100+
limits := sdktrace.NewSpanLimits()
101+
limits.EventCountLimit = 1
102+
benchmarkSpanLimits(b, limits)
103+
})
104+
105+
b.Run("LinkCountLimit", func(b *testing.B) {
106+
limits := sdktrace.NewSpanLimits()
107+
limits.LinkCountLimit = 1
108+
benchmarkSpanLimits(b, limits)
109+
})
110+
111+
b.Run("AttributePerEventCountLimit", func(b *testing.B) {
112+
limits := sdktrace.NewSpanLimits()
113+
limits.AttributePerEventCountLimit = 1
114+
benchmarkSpanLimits(b, limits)
115+
})
116+
117+
b.Run("AttributePerLinkCountLimit", func(b *testing.B) {
118+
limits := sdktrace.NewSpanLimits()
119+
limits.AttributePerLinkCountLimit = 1
120+
benchmarkSpanLimits(b, limits)
121+
})
122+
}
123+
28124
func BenchmarkSpanSetAttributesOverCapacity(b *testing.B) {
29-
tp := sdktrace.NewTracerProvider(
30-
sdktrace.WithSpanLimits(sdktrace.SpanLimits{AttributeCountLimit: 1}),
31-
)
125+
limits := sdktrace.NewSpanLimits()
126+
limits.AttributeCountLimit = 1
127+
tp := sdktrace.NewTracerProvider(sdktrace.WithSpanLimits(limits))
32128
tracer := tp.Tracer("BenchmarkSpanSetAttributesOverCapacity")
33129
ctx := context.Background()
34130
attrs := make([]attribute.KeyValue, 128)

sdk/trace/config.go

-84
This file was deleted.

sdk/trace/evictedqueue.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ func newEvictedQueue(capacity int) evictedQueue {
2929
// add adds value to the evictedQueue eq. If eq is at capacity, the oldest
3030
// queued value will be discarded and the drop count incremented.
3131
func (eq *evictedQueue) add(value interface{}) {
32-
if len(eq.queue) == eq.capacity {
32+
if eq.capacity == 0 {
33+
eq.droppedCount++
34+
return
35+
}
36+
37+
if eq.capacity > 0 && len(eq.queue) == eq.capacity {
3338
// Drop first-in while avoiding allocating more capacity to eq.queue.
3439
copy(eq.queue[:eq.capacity-1], eq.queue[1:])
3540
eq.queue = eq.queue[:eq.capacity-1]

0 commit comments

Comments
 (0)