Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update span limits to comply with specification #2637

Merged
merged 31 commits into from Mar 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5013941
PoC for span limit refactor
MrAlias Feb 23, 2022
edacdb2
Rename config.go to span_limits.go
MrAlias Feb 24, 2022
b5c5cb7
Add unit tests for truncateAttr
MrAlias Feb 24, 2022
c86faeb
Add unit tests for non-string attrs
MrAlias Feb 24, 2022
45004f5
Add span limit benchmark tests
MrAlias Feb 24, 2022
d254440
Fix lint
MrAlias Feb 24, 2022
9aa7c7f
Isolate span limit tests
MrAlias Feb 24, 2022
19a4602
Clean span limits test
MrAlias Feb 24, 2022
e498e28
Test limits on exported spans
MrAlias Feb 24, 2022
a4207f8
Remove duplicate test code
MrAlias Feb 24, 2022
006138c
Fix lint
MrAlias Feb 24, 2022
d8eb930
Add WithRawSpanLimits option
MrAlias Feb 24, 2022
6869b9c
Add test for raw and orig span limits opts
MrAlias Feb 24, 2022
f37a1f6
Add changes to changelog
MrAlias Feb 24, 2022
7995831
Add tests for span resource disabled
MrAlias Feb 24, 2022
a39debd
Test unlimited instead of default limit
MrAlias Feb 24, 2022
db95c3d
Update docs
MrAlias Feb 25, 2022
8057d17
Add fix to changelog
MrAlias Feb 25, 2022
fb742df
Fix option docs
MrAlias Feb 25, 2022
8a4be15
Do no mutate attribute
MrAlias Feb 25, 2022
a780936
Fix truncateAttr comment
MrAlias Feb 25, 2022
3bd05d9
Remake NewSpanLimits to be newEnvSpanLimits
MrAlias Feb 25, 2022
f81b753
Merge branch 'main' into unlimited-limit-vals
MrAlias Feb 25, 2022
c24c844
Update truncateAttr string slice update comment
MrAlias Feb 25, 2022
3c49ba4
Update CHANGELOG.md
MrAlias Feb 25, 2022
75a79af
Merge branch 'main' into unlimited-limit-vals
MrAlias Feb 25, 2022
047e9f5
Merge branch 'main' into unlimited-limit-vals
MrAlias Mar 1, 2022
99059ea
Merge branch 'main' into unlimited-limit-vals
MrAlias Mar 2, 2022
46e8cc3
Merge branch 'main' into unlimited-limit-vals
MrAlias Mar 2, 2022
5782668
Merge branch 'main' into unlimited-limit-vals
MrAlias Mar 2, 2022
7b57418
Merge branch 'main' into unlimited-limit-vals
MrAlias Mar 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 21 additions & 2 deletions CHANGELOG.md
Expand Up @@ -14,15 +14,26 @@ This update is a breaking change of the unstable Metrics API. Code instrumented

### Added

- Log the Exporters configuration in the TracerProviders message. (#2578)
- Added support to configure the span limits with environment variables.
The following environment variables are used. (#2606)
The following environment variables are used. (#2606, #2637)
- `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT`
- `OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT`
- `OTEL_SPAN_EVENT_COUNT_LIMIT`
- `OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT`
- `OTEL_SPAN_LINK_COUNT_LIMIT`
- `OTEL_LINK_ATTRIBUTE_COUNT_LIMIT`

If the provided environment variables are invalid (negative), the default values would be used.
- Rename the `gc` runtime name to `go` (#2560)
- Log the Exporters configuration in the TracerProviders message. (#2578)
- Add span attribute value length limit.
The new `AttributeValueLengthLimit` field is added to the `"go.opentelemetry.io/otel/sdk/trace".SpanLimits` type to configure this limit for a `TracerProvider`.
The default limit for this resource is "unlimited". (#2637)
- Add the `WithRawSpanLimits` option to `go.opentelemetry.io/otel/sdk/trace`.
This option replaces the `WithSpanLimits` option.
Zero or negative values will not be changed to the default value like `WithSpanLimits` does.
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.
Consequentially, limits should be constructed using `NewSpanLimits` and updated accordingly. (#2637)

### Changed

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

- Remove the OTLP trace exporter limit of SpanEvents when exporting. (#2616)
- Use port `4318` instead of `4317` for default for the `otlpmetrichttp` and `otlptracehttp` client. (#2614, #2625)
- Unlimited span limits are now supported (negative values). (#2636, #2637)

### Deprecated

- Deprecated `"go.opentelemetry.io/otel/sdk/trace".WithSpanLimits`.
Use `WithRawSpanLimits` instead.
That option allows setting unlimited and zero limits, this option does not.
This option will be kept until the next major version incremented release. (#2637)

## [1.4.1] - 2022-02-16

Expand Down
61 changes: 56 additions & 5 deletions sdk/internal/env/env.go
Expand Up @@ -41,20 +41,29 @@ const (
// i.e. 512
BatchSpanProcessorMaxExportBatchSizeKey = "OTEL_BSP_MAX_EXPORT_BATCH_SIZE"

// SpanAttributesCountKey
// SpanAttributeValueLengthKey
// Maximum allowed attribute value size.
SpanAttributeValueLengthKey = "OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT"

// SpanAttributeCountKey
// Maximum allowed span attribute count
// Default: 128
SpanAttributesCountKey = "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT"
SpanAttributeCountKey = "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT"

// SpanEventCountKey
// Maximum allowed span event count
// Default: 128
SpanEventCountKey = "OTEL_SPAN_EVENT_COUNT_LIMIT"

// SpanEventAttributeCountKey
// Maximum allowed attribute per span event count.
SpanEventAttributeCountKey = "OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT"

// SpanLinkCountKey
// Maximum allowed span link count
// Default: 128
SpanLinkCountKey = "OTEL_SPAN_LINK_COUNT_LIMIT"

// SpanLinkAttributeCountKey
// Maximum allowed attribute per span link count
SpanLinkAttributeCountKey = "OTEL_LINK_ATTRIBUTE_COUNT_LIMIT"
)

// IntEnvOr returns the int value of the environment variable with name key if
Expand Down Expand Up @@ -101,3 +110,45 @@ func BatchSpanProcessorMaxQueueSize(defaultValue int) int {
func BatchSpanProcessorMaxExportBatchSize(defaultValue int) int {
return IntEnvOr(BatchSpanProcessorMaxExportBatchSizeKey, defaultValue)
}

// SpanAttributeValueLength returns the environment variable value for the
// OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT key if it exists, otherwise
// defaultValue is returned.
func SpanAttributeValueLength(defaultValue int) int {
return IntEnvOr(SpanAttributeValueLengthKey, defaultValue)
}

// SpanAttributeCount returns the environment variable value for the
// OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT key if it exists, otherwise defaultValue is
// returned.
func SpanAttributeCount(defaultValue int) int {
return IntEnvOr(SpanAttributeCountKey, defaultValue)
}

// SpanEventCount returns the environment variable value for the
// OTEL_SPAN_EVENT_COUNT_LIMIT key if it exists, otherwise defaultValue is
// returned.
func SpanEventCount(defaultValue int) int {
return IntEnvOr(SpanEventCountKey, defaultValue)
}

// SpanEventAttributeCount returns the environment variable value for the
// OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT key if it exists, otherwise defaultValue
// is returned.
func SpanEventAttributeCount(defaultValue int) int {
return IntEnvOr(SpanEventAttributeCountKey, defaultValue)
}

// SpanLinkCount returns the environment variable value for the
// OTEL_SPAN_LINK_COUNT_LIMIT key if it exists, otherwise defaultValue is
// returned.
func SpanLinkCount(defaultValue int) int {
return IntEnvOr(SpanLinkCountKey, defaultValue)
}

// SpanLinkAttributeCount returns the environment variable value for the
// OTEL_LINK_ATTRIBUTE_COUNT_LIMIT key if it exists, otherwise defaultValue is
// returned.
func SpanLinkAttributeCount(defaultValue int) int {
return IntEnvOr(SpanLinkAttributeCountKey, defaultValue)
}
102 changes: 99 additions & 3 deletions sdk/trace/benchmark_test.go
Expand Up @@ -25,10 +25,106 @@ import (
"go.opentelemetry.io/otel/trace"
)

func benchmarkSpanLimits(b *testing.B, limits sdktrace.SpanLimits) {
tp := sdktrace.NewTracerProvider(sdktrace.WithSpanLimits(limits))
tracer := tp.Tracer(b.Name())
ctx := context.Background()

const count = 8

attrs := []attribute.KeyValue{
attribute.Bool("bool", true),
attribute.BoolSlice("boolSlice", []bool{true, false}),
attribute.Int("int", 42),
attribute.IntSlice("intSlice", []int{42, -1}),
attribute.Int64("int64", 42),
attribute.Int64Slice("int64Slice", []int64{42, -1}),
attribute.Float64("float64", 42),
attribute.Float64Slice("float64Slice", []float64{42, -1}),
attribute.String("string", "value"),
attribute.StringSlice("stringSlice", []string{"value", "value-1"}),
}

links := make([]trace.Link, count)
for i := range links {
links[i] = trace.Link{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: [16]byte{0x01},
SpanID: [8]byte{0x01},
}),
Attributes: attrs,
}
}

events := make([]struct {
name string
attr []attribute.KeyValue
}, count)
for i := range events {
events[i] = struct {
name string
attr []attribute.KeyValue
}{
name: fmt.Sprintf("event-%d", i),
attr: attrs,
}
}

b.ReportAllocs()
b.ResetTimer()

for i := 0; i < b.N; i++ {
_, span := tracer.Start(ctx, "span-name", trace.WithLinks(links...))
span.SetAttributes(attrs...)
for _, e := range events {
span.AddEvent(e.name, trace.WithAttributes(e.attr...))
}
span.End()
}
}

func BenchmarkSpanLimits(b *testing.B) {
b.Run("AttributeValueLengthLimit", func(b *testing.B) {
limits := sdktrace.NewSpanLimits()
limits.AttributeValueLengthLimit = 2
benchmarkSpanLimits(b, limits)
})

b.Run("AttributeCountLimit", func(b *testing.B) {
limits := sdktrace.NewSpanLimits()
limits.AttributeCountLimit = 1
benchmarkSpanLimits(b, limits)
})

b.Run("EventCountLimit", func(b *testing.B) {
limits := sdktrace.NewSpanLimits()
limits.EventCountLimit = 1
benchmarkSpanLimits(b, limits)
})

b.Run("LinkCountLimit", func(b *testing.B) {
limits := sdktrace.NewSpanLimits()
limits.LinkCountLimit = 1
benchmarkSpanLimits(b, limits)
})

b.Run("AttributePerEventCountLimit", func(b *testing.B) {
limits := sdktrace.NewSpanLimits()
limits.AttributePerEventCountLimit = 1
benchmarkSpanLimits(b, limits)
})

b.Run("AttributePerLinkCountLimit", func(b *testing.B) {
limits := sdktrace.NewSpanLimits()
limits.AttributePerLinkCountLimit = 1
benchmarkSpanLimits(b, limits)
})
}

func BenchmarkSpanSetAttributesOverCapacity(b *testing.B) {
tp := sdktrace.NewTracerProvider(
sdktrace.WithSpanLimits(sdktrace.SpanLimits{AttributeCountLimit: 1}),
)
limits := sdktrace.NewSpanLimits()
limits.AttributeCountLimit = 1
tp := sdktrace.NewTracerProvider(sdktrace.WithSpanLimits(limits))
tracer := tp.Tracer("BenchmarkSpanSetAttributesOverCapacity")
ctx := context.Background()
attrs := make([]attribute.KeyValue, 128)
Expand Down
84 changes: 0 additions & 84 deletions sdk/trace/config.go

This file was deleted.

7 changes: 6 additions & 1 deletion sdk/trace/evictedqueue.go
Expand Up @@ -29,7 +29,12 @@ func newEvictedQueue(capacity int) evictedQueue {
// add adds value to the evictedQueue eq. If eq is at capacity, the oldest
// queued value will be discarded and the drop count incremented.
func (eq *evictedQueue) add(value interface{}) {
if len(eq.queue) == eq.capacity {
if eq.capacity == 0 {
eq.droppedCount++
return
}

if eq.capacity > 0 && len(eq.queue) == eq.capacity {
// Drop first-in while avoiding allocating more capacity to eq.queue.
copy(eq.queue[:eq.capacity-1], eq.queue[1:])
eq.queue = eq.queue[:eq.capacity-1]
Expand Down