1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2024-12-12 10:04:29 +02:00
opentelemetry-go/sdk/trace/span_limits_test.go
Tyler Yahn 0d0a7320e6
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 <a9@aneurysm9.com>

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>
2022-03-03 07:56:07 -08:00

284 lines
7.7 KiB
Go

// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package trace
import (
"context"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
ottest "go.opentelemetry.io/otel/internal/internaltest"
"go.opentelemetry.io/otel/sdk/internal/env"
"go.opentelemetry.io/otel/trace"
)
func TestSettingSpanLimits(t *testing.T) {
envLimits := func(val string) map[string]string {
return map[string]string{
env.SpanAttributeValueLengthKey: val,
env.SpanEventCountKey: val,
env.SpanAttributeCountKey: val,
env.SpanLinkCountKey: val,
env.SpanEventAttributeCountKey: val,
env.SpanLinkAttributeCountKey: val,
}
}
limits := func(n int) *SpanLimits {
lims := NewSpanLimits()
lims.AttributeValueLengthLimit = n
lims.AttributeCountLimit = n
lims.EventCountLimit = n
lims.LinkCountLimit = n
lims.AttributePerEventCountLimit = n
lims.AttributePerLinkCountLimit = n
return &lims
}
tests := []struct {
name string
env map[string]string
opt *SpanLimits
rawOpt *SpanLimits
want SpanLimits
}{
{
name: "defaults",
want: NewSpanLimits(),
},
{
name: "env",
env: envLimits("42"),
want: *(limits(42)),
},
{
name: "opt",
opt: limits(42),
want: *(limits(42)),
},
{
name: "raw-opt",
rawOpt: limits(42),
want: *(limits(42)),
},
{
name: "opt-override",
env: envLimits("-2"),
// Option take priority.
opt: limits(43),
want: *(limits(43)),
},
{
name: "raw-opt-override",
env: envLimits("-2"),
// Option take priority.
rawOpt: limits(43),
want: *(limits(43)),
},
{
name: "last-opt-wins",
opt: limits(-2),
rawOpt: limits(-3),
want: *(limits(-3)),
},
{
name: "env(unlimited)",
// OTel spec says negative SpanLinkAttributeCountKey is invalid,
// but since we will revert to the default (unlimited) which uses
// negative values to signal this than this value is expected to
// pass through.
env: envLimits("-1"),
want: *(limits(-1)),
},
{
name: "opt(unlimited)",
// Corrects to defaults.
opt: limits(-1),
want: NewSpanLimits(),
},
{
name: "raw-opt(unlimited)",
rawOpt: limits(-1),
want: *(limits(-1)),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.env != nil {
es := ottest.NewEnvStore()
t.Cleanup(func() { require.NoError(t, es.Restore()) })
for k, v := range test.env {
es.Record(k)
require.NoError(t, os.Setenv(k, v))
}
}
var opts []TracerProviderOption
if test.opt != nil {
opts = append(opts, WithSpanLimits(*test.opt))
}
if test.rawOpt != nil {
opts = append(opts, WithRawSpanLimits(*test.rawOpt))
}
assert.Equal(t, test.want, NewTracerProvider(opts...).spanLimits)
})
}
}
type recorder []ReadOnlySpan
func (r *recorder) OnStart(context.Context, ReadWriteSpan) {}
func (r *recorder) OnEnd(s ReadOnlySpan) { *r = append(*r, s) }
func (r *recorder) ForceFlush(context.Context) error { return nil }
func (r *recorder) Shutdown(context.Context) error { return nil }
func testSpanLimits(t *testing.T, limits SpanLimits) ReadOnlySpan {
rec := new(recorder)
tp := NewTracerProvider(WithRawSpanLimits(limits), WithSpanProcessor(rec))
tracer := tp.Tracer("testSpanLimits")
ctx := context.Background()
a := []attribute.KeyValue{attribute.Bool("one", true), attribute.Bool("two", true)}
l := trace.Link{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: [16]byte{0x01},
SpanID: [8]byte{0x01},
}),
Attributes: a,
}
_, span := tracer.Start(ctx, "span-name", trace.WithLinks(l, l))
span.SetAttributes(
attribute.String("string", "abc"),
attribute.StringSlice("stringSlice", []string{"abc", "def"}),
)
span.AddEvent("event 1", trace.WithAttributes(a...))
span.AddEvent("event 2", trace.WithAttributes(a...))
span.End()
require.NoError(t, tp.Shutdown(ctx))
require.Len(t, *rec, 1, "exported spans")
return (*rec)[0]
}
func TestSpanLimits(t *testing.T) {
t.Run("AttributeValueLengthLimit", func(t *testing.T) {
limits := NewSpanLimits()
// Unlimited.
limits.AttributeValueLengthLimit = -1
attrs := testSpanLimits(t, limits).Attributes()
assert.Contains(t, attrs, attribute.String("string", "abc"))
assert.Contains(t, attrs, attribute.StringSlice("stringSlice", []string{"abc", "def"}))
limits.AttributeValueLengthLimit = 2
attrs = testSpanLimits(t, limits).Attributes()
// Ensure string and string slice attributes are truncated.
assert.Contains(t, attrs, attribute.String("string", "ab"))
assert.Contains(t, attrs, attribute.StringSlice("stringSlice", []string{"ab", "de"}))
limits.AttributeValueLengthLimit = 0
attrs = testSpanLimits(t, limits).Attributes()
assert.Contains(t, attrs, attribute.String("string", ""))
assert.Contains(t, attrs, attribute.StringSlice("stringSlice", []string{"", ""}))
})
t.Run("AttributeCountLimit", func(t *testing.T) {
limits := NewSpanLimits()
// Unlimited.
limits.AttributeCountLimit = -1
assert.Len(t, testSpanLimits(t, limits).Attributes(), 2)
limits.AttributeCountLimit = 1
assert.Len(t, testSpanLimits(t, limits).Attributes(), 1)
// Ensure this can be disabled.
limits.AttributeCountLimit = 0
assert.Len(t, testSpanLimits(t, limits).Attributes(), 0)
})
t.Run("EventCountLimit", func(t *testing.T) {
limits := NewSpanLimits()
// Unlimited.
limits.EventCountLimit = -1
assert.Len(t, testSpanLimits(t, limits).Events(), 2)
limits.EventCountLimit = 1
assert.Len(t, testSpanLimits(t, limits).Events(), 1)
// Ensure this can be disabled.
limits.EventCountLimit = 0
assert.Len(t, testSpanLimits(t, limits).Events(), 0)
})
t.Run("AttributePerEventCountLimit", func(t *testing.T) {
limits := NewSpanLimits()
// Unlimited.
limits.AttributePerEventCountLimit = -1
for _, e := range testSpanLimits(t, limits).Events() {
assert.Len(t, e.Attributes, 2)
}
limits.AttributePerEventCountLimit = 1
for _, e := range testSpanLimits(t, limits).Events() {
assert.Len(t, e.Attributes, 1)
}
// Ensure this can be disabled.
limits.AttributePerEventCountLimit = 0
for _, e := range testSpanLimits(t, limits).Events() {
assert.Len(t, e.Attributes, 0)
}
})
t.Run("LinkCountLimit", func(t *testing.T) {
limits := NewSpanLimits()
// Unlimited.
limits.LinkCountLimit = -1
assert.Len(t, testSpanLimits(t, limits).Links(), 2)
limits.LinkCountLimit = 1
assert.Len(t, testSpanLimits(t, limits).Links(), 1)
// Ensure this can be disabled.
limits.LinkCountLimit = 0
assert.Len(t, testSpanLimits(t, limits).Links(), 0)
})
t.Run("AttributePerLinkCountLimit", func(t *testing.T) {
limits := NewSpanLimits()
// Unlimited.
limits.AttributePerLinkCountLimit = -1
for _, l := range testSpanLimits(t, limits).Links() {
assert.Len(t, l.Attributes, 2)
}
limits.AttributePerLinkCountLimit = 1
for _, l := range testSpanLimits(t, limits).Links() {
assert.Len(t, l.Attributes, 1)
}
// Ensure this can be disabled.
limits.AttributePerLinkCountLimit = 0
for _, l := range testSpanLimits(t, limits).Links() {
assert.Len(t, l.Attributes, 0)
}
})
}