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

Support general attribute limits for spans #2677

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -57,6 +57,7 @@ Code instrumented with the `go.opentelemetry.io/otel/metric` will need to be mod
- Remove the OTLP trace exporter limit of SpanEvents when exporting. (#2616)
- Default to port `4318` instead of `4317` for the `otlpmetrichttp` and `otlptracehttp` client. (#2614, #2625)
- Unlimited span limits are now supported (negative values). (#2636, #2637)
- Fallback to general attribute limits when span specific ones are not set in the environment. (#2675, #2677)

### Deprecated

Expand Down
54 changes: 43 additions & 11 deletions sdk/internal/env/env.go
Expand Up @@ -41,31 +41,61 @@ const (
// i.e. 512
BatchSpanProcessorMaxExportBatchSizeKey = "OTEL_BSP_MAX_EXPORT_BATCH_SIZE"

// SpanAttributeValueLengthKey
// AttributeValueLengthKey
// Maximum allowed attribute value size.
AttributeValueLengthKey = "OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT"

// AttributeCountKey
// Maximum allowed span attribute count
AttributeCountKey = "OTEL_ATTRIBUTE_COUNT_LIMIT"

// SpanAttributeValueLengthKey
// Maximum allowed attribute value size for a span.
SpanAttributeValueLengthKey = "OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT"

// SpanAttributeCountKey
// Maximum allowed span attribute count
// Maximum allowed span attribute count for a span.
SpanAttributeCountKey = "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT"

// SpanEventCountKey
// Maximum allowed span event count
// Maximum allowed span event count.
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
// Maximum allowed span link count.
SpanLinkCountKey = "OTEL_SPAN_LINK_COUNT_LIMIT"

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

// firstInt returns the value of the first matching environment variable from
// keys. If the value is not an integer or no match is found, defaultValue is
// returned.
func firstInt(defaultValue int, keys ...string) int {
for _, key := range keys {
value, ok := os.LookupEnv(key)
if !ok {
continue
}

intValue, err := strconv.Atoi(value)
if err != nil {
global.Info("Got invalid value, number value expected.", key, value)
return defaultValue
}

return intValue
}

return defaultValue
}

// IntEnvOr returns the int value of the environment variable with name key if
// it exists and the value is an int. Otherwise, defaultValue is returned.
func IntEnvOr(key string, defaultValue int) int {
Expand Down Expand Up @@ -112,17 +142,19 @@ func BatchSpanProcessorMaxExportBatchSize(defaultValue int) int {
}

// SpanAttributeValueLength returns the environment variable value for the
// OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT key if it exists, otherwise
// defaultValue is returned.
// OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT key if it exists. Otherwise, the
// environment variable value for OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT is
// returned or defaultValue if that is not set.
func SpanAttributeValueLength(defaultValue int) int {
return IntEnvOr(SpanAttributeValueLengthKey, defaultValue)
return firstInt(defaultValue, SpanAttributeValueLengthKey, AttributeValueLengthKey)
}

// SpanAttributeCount returns the environment variable value for the
// OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT key if it exists, otherwise defaultValue is
// returned.
// OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT key if it exists. Otherwise, the
// environment variable value for OTEL_ATTRIBUTE_COUNT_LIMIT is returned or
// defaultValue if that is not set.
func SpanAttributeCount(defaultValue int) int {
return IntEnvOr(SpanAttributeCountKey, defaultValue)
return firstInt(defaultValue, SpanAttributeCountKey, AttributeCountKey)
}

// SpanEventCount returns the environment variable value for the
Expand Down
103 changes: 82 additions & 21 deletions sdk/internal/env/env_test.go
Expand Up @@ -24,37 +24,98 @@ import (
ottest "go.opentelemetry.io/otel/internal/internaltest"
)

func TestIntEnvOr(t *testing.T) {
func TestEnvParse(t *testing.T) {
testCases := []struct {
name string
envValue string
defaultValue int
expectedValue int
name string
keys []string
f func(int) int
}{
{
name: "IntEnvOrTest - Basic",
envValue: "2500",
defaultValue: 500,
expectedValue: 2500,
name: "BatchSpanProcessorScheduleDelay",
keys: []string{BatchSpanProcessorScheduleDelayKey},
f: BatchSpanProcessorScheduleDelay,
},

{
name: "BatchSpanProcessorExportTimeout",
keys: []string{BatchSpanProcessorExportTimeoutKey},
f: BatchSpanProcessorExportTimeout,
},

{
name: "BatchSpanProcessorMaxQueueSize",
keys: []string{BatchSpanProcessorMaxQueueSizeKey},
f: BatchSpanProcessorMaxQueueSize,
},

{
name: "BatchSpanProcessorMaxExportBatchSize",
keys: []string{BatchSpanProcessorMaxExportBatchSizeKey},
f: BatchSpanProcessorMaxExportBatchSize,
},

{
name: "SpanAttributeValueLength",
keys: []string{SpanAttributeValueLengthKey, AttributeValueLengthKey},
f: SpanAttributeValueLength,
},

{
name: "SpanAttributeCount",
keys: []string{SpanAttributeCountKey, AttributeCountKey},
f: SpanAttributeCount,
},

{
name: "SpanEventCount",
keys: []string{SpanEventCountKey},
f: SpanEventCount,
},

{
name: "IntEnvOrTest - Invalid Number",
envValue: "localhost",
defaultValue: 500,
expectedValue: 500,
name: "SpanEventAttributeCount",
keys: []string{SpanEventAttributeCountKey},
f: SpanEventAttributeCount,
},

{
name: "SpanLinkCount",
keys: []string{SpanLinkCountKey},
f: SpanLinkCount,
},

{
name: "SpanLinkAttributeCount",
keys: []string{SpanLinkAttributeCountKey},
f: SpanLinkAttributeCount,
},
}

envStore := ottest.NewEnvStore()
envStore.Record(BatchSpanProcessorMaxQueueSizeKey)
defer func() {
require.NoError(t, envStore.Restore())
}()
const (
defVal = 500
envVal = 2500
envValStr = "2500"
invalid = "localhost"
)

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
require.NoError(t, os.Setenv(BatchSpanProcessorMaxQueueSizeKey, tc.envValue))
actualValue := BatchSpanProcessorMaxQueueSize(tc.defaultValue)
assert.Equal(t, tc.expectedValue, actualValue)
for _, key := range tc.keys {
t.Run(key, func(t *testing.T) {
envStore := ottest.NewEnvStore()
t.Cleanup(func() { require.NoError(t, envStore.Restore()) })
envStore.Record(key)

assert.Equal(t, defVal, tc.f(defVal), "environment variable unset")

require.NoError(t, os.Setenv(key, envValStr))
assert.Equal(t, envVal, tc.f(defVal), "environment variable set/valid")

require.NoError(t, os.Setenv(key, invalid))
assert.Equal(t, defVal, tc.f(defVal), "invalid value")
})

}
})
}
}