...

Source file src/go.opentelemetry.io/otel/sdk/trace/span_limits_test.go

Documentation: go.opentelemetry.io/otel/sdk/trace

     1  // Copyright The OpenTelemetry Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package trace
    16  
    17  import (
    18  	"context"
    19  	"os"
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  
    25  	"go.opentelemetry.io/otel/attribute"
    26  	"go.opentelemetry.io/otel/sdk/internal/env"
    27  	ottest "go.opentelemetry.io/otel/sdk/internal/internaltest"
    28  	"go.opentelemetry.io/otel/trace"
    29  )
    30  
    31  func TestSettingSpanLimits(t *testing.T) {
    32  	envLimits := func(val string) map[string]string {
    33  		return map[string]string{
    34  			env.SpanAttributeValueLengthKey: val,
    35  			env.SpanEventCountKey:           val,
    36  			env.SpanAttributeCountKey:       val,
    37  			env.SpanLinkCountKey:            val,
    38  			env.SpanEventAttributeCountKey:  val,
    39  			env.SpanLinkAttributeCountKey:   val,
    40  		}
    41  	}
    42  
    43  	limits := func(n int) *SpanLimits {
    44  		lims := NewSpanLimits()
    45  		lims.AttributeValueLengthLimit = n
    46  		lims.AttributeCountLimit = n
    47  		lims.EventCountLimit = n
    48  		lims.LinkCountLimit = n
    49  		lims.AttributePerEventCountLimit = n
    50  		lims.AttributePerLinkCountLimit = n
    51  		return &lims
    52  	}
    53  
    54  	tests := []struct {
    55  		name   string
    56  		env    map[string]string
    57  		opt    *SpanLimits
    58  		rawOpt *SpanLimits
    59  		want   SpanLimits
    60  	}{
    61  		{
    62  			name: "defaults",
    63  			want: NewSpanLimits(),
    64  		},
    65  		{
    66  			name: "env",
    67  			env:  envLimits("42"),
    68  			want: *(limits(42)),
    69  		},
    70  		{
    71  			name: "opt",
    72  			opt:  limits(42),
    73  			want: *(limits(42)),
    74  		},
    75  		{
    76  			name:   "raw-opt",
    77  			rawOpt: limits(42),
    78  			want:   *(limits(42)),
    79  		},
    80  		{
    81  			name: "opt-override",
    82  			env:  envLimits("-2"),
    83  			// Option take priority.
    84  			opt:  limits(43),
    85  			want: *(limits(43)),
    86  		},
    87  		{
    88  			name: "raw-opt-override",
    89  			env:  envLimits("-2"),
    90  			// Option take priority.
    91  			rawOpt: limits(43),
    92  			want:   *(limits(43)),
    93  		},
    94  		{
    95  			name:   "last-opt-wins",
    96  			opt:    limits(-2),
    97  			rawOpt: limits(-3),
    98  			want:   *(limits(-3)),
    99  		},
   100  		{
   101  			name: "env(unlimited)",
   102  			// OTel spec says negative SpanLinkAttributeCountKey is invalid,
   103  			// but since we will revert to the default (unlimited) which uses
   104  			// negative values to signal this than this value is expected to
   105  			// pass through.
   106  			env:  envLimits("-1"),
   107  			want: *(limits(-1)),
   108  		},
   109  		{
   110  			name: "opt(unlimited)",
   111  			// Corrects to defaults.
   112  			opt:  limits(-1),
   113  			want: NewSpanLimits(),
   114  		},
   115  		{
   116  			name:   "raw-opt(unlimited)",
   117  			rawOpt: limits(-1),
   118  			want:   *(limits(-1)),
   119  		},
   120  	}
   121  
   122  	for _, test := range tests {
   123  		t.Run(test.name, func(t *testing.T) {
   124  			if test.env != nil {
   125  				es := ottest.NewEnvStore()
   126  				t.Cleanup(func() { require.NoError(t, es.Restore()) })
   127  				for k, v := range test.env {
   128  					es.Record(k)
   129  					require.NoError(t, os.Setenv(k, v))
   130  				}
   131  			}
   132  
   133  			var opts []TracerProviderOption
   134  			if test.opt != nil {
   135  				opts = append(opts, WithSpanLimits(*test.opt))
   136  			}
   137  			if test.rawOpt != nil {
   138  				opts = append(opts, WithRawSpanLimits(*test.rawOpt))
   139  			}
   140  
   141  			assert.Equal(t, test.want, NewTracerProvider(opts...).spanLimits)
   142  		})
   143  	}
   144  }
   145  
   146  type recorder []ReadOnlySpan
   147  
   148  func (r *recorder) OnStart(context.Context, ReadWriteSpan) {}
   149  func (r *recorder) OnEnd(s ReadOnlySpan)                   { *r = append(*r, s) }
   150  func (r *recorder) ForceFlush(context.Context) error       { return nil }
   151  func (r *recorder) Shutdown(context.Context) error         { return nil }
   152  
   153  func testSpanLimits(t *testing.T, limits SpanLimits) ReadOnlySpan {
   154  	rec := new(recorder)
   155  	tp := NewTracerProvider(WithRawSpanLimits(limits), WithSpanProcessor(rec))
   156  	tracer := tp.Tracer("testSpanLimits")
   157  
   158  	ctx := context.Background()
   159  	a := []attribute.KeyValue{attribute.Bool("one", true), attribute.Bool("two", true)}
   160  	l := trace.Link{
   161  		SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
   162  			TraceID: [16]byte{0x01},
   163  			SpanID:  [8]byte{0x01},
   164  		}),
   165  		Attributes: a,
   166  	}
   167  	_, span := tracer.Start(ctx, "span-name", trace.WithLinks(l, l))
   168  	span.SetAttributes(
   169  		attribute.String("string", "abc"),
   170  		attribute.StringSlice("stringSlice", []string{"abc", "def"}),
   171  		attribute.String("euro", "€"), // this is a 3-byte rune
   172  	)
   173  	span.AddEvent("event 1", trace.WithAttributes(a...))
   174  	span.AddEvent("event 2", trace.WithAttributes(a...))
   175  	span.End()
   176  	require.NoError(t, tp.Shutdown(ctx))
   177  
   178  	require.Len(t, *rec, 1, "exported spans")
   179  	return (*rec)[0]
   180  }
   181  
   182  func TestSpanLimits(t *testing.T) {
   183  	t.Run("AttributeValueLengthLimit", func(t *testing.T) {
   184  		limits := NewSpanLimits()
   185  		// Unlimited.
   186  		limits.AttributeValueLengthLimit = -1
   187  		attrs := testSpanLimits(t, limits).Attributes()
   188  		assert.Contains(t, attrs, attribute.String("string", "abc"))
   189  		assert.Contains(t, attrs, attribute.StringSlice("stringSlice", []string{"abc", "def"}))
   190  		assert.Contains(t, attrs, attribute.String("euro", "€"))
   191  
   192  		limits.AttributeValueLengthLimit = 2
   193  		attrs = testSpanLimits(t, limits).Attributes()
   194  		// Ensure string and string slice attributes are truncated.
   195  		assert.Contains(t, attrs, attribute.String("string", "ab"))
   196  		assert.Contains(t, attrs, attribute.StringSlice("stringSlice", []string{"ab", "de"}))
   197  		assert.Contains(t, attrs, attribute.String("euro", ""))
   198  
   199  		limits.AttributeValueLengthLimit = 0
   200  		attrs = testSpanLimits(t, limits).Attributes()
   201  		assert.Contains(t, attrs, attribute.String("string", ""))
   202  		assert.Contains(t, attrs, attribute.StringSlice("stringSlice", []string{"", ""}))
   203  		assert.Contains(t, attrs, attribute.String("euro", ""))
   204  	})
   205  
   206  	t.Run("AttributeCountLimit", func(t *testing.T) {
   207  		limits := NewSpanLimits()
   208  		// Unlimited.
   209  		limits.AttributeCountLimit = -1
   210  		assert.Len(t, testSpanLimits(t, limits).Attributes(), 3)
   211  
   212  		limits.AttributeCountLimit = 1
   213  		assert.Len(t, testSpanLimits(t, limits).Attributes(), 1)
   214  
   215  		// Ensure this can be disabled.
   216  		limits.AttributeCountLimit = 0
   217  		assert.Len(t, testSpanLimits(t, limits).Attributes(), 0)
   218  	})
   219  
   220  	t.Run("EventCountLimit", func(t *testing.T) {
   221  		limits := NewSpanLimits()
   222  		// Unlimited.
   223  		limits.EventCountLimit = -1
   224  		assert.Len(t, testSpanLimits(t, limits).Events(), 2)
   225  
   226  		limits.EventCountLimit = 1
   227  		assert.Len(t, testSpanLimits(t, limits).Events(), 1)
   228  
   229  		// Ensure this can be disabled.
   230  		limits.EventCountLimit = 0
   231  		assert.Len(t, testSpanLimits(t, limits).Events(), 0)
   232  	})
   233  
   234  	t.Run("AttributePerEventCountLimit", func(t *testing.T) {
   235  		limits := NewSpanLimits()
   236  		// Unlimited.
   237  		limits.AttributePerEventCountLimit = -1
   238  		for _, e := range testSpanLimits(t, limits).Events() {
   239  			assert.Len(t, e.Attributes, 2)
   240  		}
   241  
   242  		limits.AttributePerEventCountLimit = 1
   243  		for _, e := range testSpanLimits(t, limits).Events() {
   244  			assert.Len(t, e.Attributes, 1)
   245  		}
   246  
   247  		// Ensure this can be disabled.
   248  		limits.AttributePerEventCountLimit = 0
   249  		for _, e := range testSpanLimits(t, limits).Events() {
   250  			assert.Len(t, e.Attributes, 0)
   251  		}
   252  	})
   253  
   254  	t.Run("LinkCountLimit", func(t *testing.T) {
   255  		limits := NewSpanLimits()
   256  		// Unlimited.
   257  		limits.LinkCountLimit = -1
   258  		assert.Len(t, testSpanLimits(t, limits).Links(), 2)
   259  
   260  		limits.LinkCountLimit = 1
   261  		assert.Len(t, testSpanLimits(t, limits).Links(), 1)
   262  
   263  		// Ensure this can be disabled.
   264  		limits.LinkCountLimit = 0
   265  		assert.Len(t, testSpanLimits(t, limits).Links(), 0)
   266  	})
   267  
   268  	t.Run("AttributePerLinkCountLimit", func(t *testing.T) {
   269  		limits := NewSpanLimits()
   270  		// Unlimited.
   271  		limits.AttributePerLinkCountLimit = -1
   272  		for _, l := range testSpanLimits(t, limits).Links() {
   273  			assert.Len(t, l.Attributes, 2)
   274  		}
   275  
   276  		limits.AttributePerLinkCountLimit = 1
   277  		for _, l := range testSpanLimits(t, limits).Links() {
   278  			assert.Len(t, l.Attributes, 1)
   279  		}
   280  
   281  		// Ensure this can be disabled.
   282  		limits.AttributePerLinkCountLimit = 0
   283  		for _, l := range testSpanLimits(t, limits).Links() {
   284  			assert.Len(t, l.Attributes, 0)
   285  		}
   286  	})
   287  }
   288  

View as plain text