You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-08-10 22:31:50 +02:00
sdk/metric: Add WithCardinalityLimit option (#6996)
Fixes #6976 Towards #6887 ## What - A new configuration field for cardinality limits is added to the SDK. - Users can set cardinality limits via code - Default value of 0(no limit) is applied if no value is provided. - Unit tests validate the configuration behavior. ## Additional - Issue created regarding the missing environment variable for the cardinality limit: [opentelemetry-specification#4586](https://github.com/open-telemetry/opentelemetry-specification/issues/4586) --------- Co-authored-by: Robert Pająk <pellared@hotmail.com> Co-authored-by: Damien Mathieu <42@dmathieu.com> Co-authored-by: Cijo Thomas <cithomas@microsoft.com> Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
ac860229c6
commit
c23a0667de
@@ -41,6 +41,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||||||
- `RPCGRPCResponseMetadata`
|
- `RPCGRPCResponseMetadata`
|
||||||
- Add `ErrorType` attribute helper function to the `go.opentelmetry.io/otel/semconv/v1.34.0` package. (#6962)
|
- Add `ErrorType` attribute helper function to the `go.opentelmetry.io/otel/semconv/v1.34.0` package. (#6962)
|
||||||
- Add `WithAllowKeyDuplication` in `go.opentelemetry.io/otel/sdk/log` which can be used to disable deduplication for log records. (#6968)
|
- Add `WithAllowKeyDuplication` in `go.opentelemetry.io/otel/sdk/log` which can be used to disable deduplication for log records. (#6968)
|
||||||
|
- Add `WithCardinalityLimit` option to configure the cardinality limit in `go.opentelemetry.io/otel/sdk/metric`. (#6996)
|
||||||
- Add `Clone` method to `Record` in `go.opentelemetry.io/otel/log` that returns a copy of the record with no shared state. (#7001)
|
- Add `Clone` method to `Record` in `go.opentelemetry.io/otel/log` that returns a copy of the record with no shared state. (#7001)
|
||||||
- The `go.opentelemetry.io/otel/semconv/v1.36.0` package.
|
- The `go.opentelemetry.io/otel/semconv/v1.36.0` package.
|
||||||
The package contains semantic conventions from the `v1.36.0` version of the OpenTelemetry Semantic Conventions.
|
The package contains semantic conventions from the `v1.36.0` version of the OpenTelemetry Semantic Conventions.
|
||||||
|
@@ -7,6 +7,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -21,8 +22,11 @@ type config struct {
|
|||||||
readers []Reader
|
readers []Reader
|
||||||
views []View
|
views []View
|
||||||
exemplarFilter exemplar.Filter
|
exemplarFilter exemplar.Filter
|
||||||
|
cardinalityLimit int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultCardinalityLimit = 0
|
||||||
|
|
||||||
// readerSignals returns a force-flush and shutdown function for a
|
// readerSignals returns a force-flush and shutdown function for a
|
||||||
// MeterProvider to call in their respective options. All Readers c contains
|
// MeterProvider to call in their respective options. All Readers c contains
|
||||||
// will have their force-flush and shutdown methods unified into returned
|
// will have their force-flush and shutdown methods unified into returned
|
||||||
@@ -71,6 +75,7 @@ func newConfig(options []Option) config {
|
|||||||
conf := config{
|
conf := config{
|
||||||
res: resource.Default(),
|
res: resource.Default(),
|
||||||
exemplarFilter: exemplar.TraceBasedFilter,
|
exemplarFilter: exemplar.TraceBasedFilter,
|
||||||
|
cardinalityLimit: cardinalityLimitFromEnv(),
|
||||||
}
|
}
|
||||||
for _, o := range meterProviderOptionsFromEnv() {
|
for _, o := range meterProviderOptionsFromEnv() {
|
||||||
conf = o.apply(conf)
|
conf = o.apply(conf)
|
||||||
@@ -155,6 +160,23 @@ func WithExemplarFilter(filter exemplar.Filter) Option {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithCardinalityLimit sets the cardinality limit for the MeterProvider.
|
||||||
|
//
|
||||||
|
// The cardinality limit is the hard limit on the number of metric datapoints
|
||||||
|
// that can be collected for a single instrument in a single collect cycle.
|
||||||
|
//
|
||||||
|
// By default, there is no limit applied.
|
||||||
|
//
|
||||||
|
// Setting this to a zero or negative value means no limit is applied.
|
||||||
|
func WithCardinalityLimit(limit int) Option {
|
||||||
|
// For backward compatibility, the environment variable `OTEL_GO_X_CARDINALITY_LIMIT`
|
||||||
|
// can also be used to set this value.
|
||||||
|
return optionFunc(func(cfg config) config {
|
||||||
|
cfg.cardinalityLimit = limit
|
||||||
|
return cfg
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func meterProviderOptionsFromEnv() []Option {
|
func meterProviderOptionsFromEnv() []Option {
|
||||||
var opts []Option
|
var opts []Option
|
||||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/d4b241f451674e8f611bb589477680341006ad2b/specification/configuration/sdk-environment-variables.md#exemplar
|
// https://github.com/open-telemetry/opentelemetry-specification/blob/d4b241f451674e8f611bb589477680341006ad2b/specification/configuration/sdk-environment-variables.md#exemplar
|
||||||
@@ -170,3 +192,17 @@ func meterProviderOptionsFromEnv() []Option {
|
|||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cardinalityLimitFromEnv() int {
|
||||||
|
const cardinalityLimitKey = "OTEL_GO_X_CARDINALITY_LIMIT"
|
||||||
|
v := strings.TrimSpace(os.Getenv(cardinalityLimitKey))
|
||||||
|
if v == "" {
|
||||||
|
return defaultCardinalityLimit
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(v)
|
||||||
|
if err != nil {
|
||||||
|
otel.Handle(err)
|
||||||
|
return defaultCardinalityLimit
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
@@ -306,6 +306,54 @@ func TestWithExemplarFilterOff(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWithCardinalityLimit(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
envValue string
|
||||||
|
options []Option
|
||||||
|
expectedLimit int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "only cardinality limit from option",
|
||||||
|
envValue: "",
|
||||||
|
options: []Option{WithCardinalityLimit(1000)},
|
||||||
|
expectedLimit: 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cardinality limit from option overrides env",
|
||||||
|
envValue: "500",
|
||||||
|
options: []Option{WithCardinalityLimit(1000)},
|
||||||
|
expectedLimit: 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cardinality limit from env",
|
||||||
|
envValue: "1234",
|
||||||
|
options: []Option{},
|
||||||
|
expectedLimit: 1234,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid env value uses default",
|
||||||
|
envValue: "not-a-number",
|
||||||
|
options: []Option{},
|
||||||
|
expectedLimit: defaultCardinalityLimit,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty env and no option uses default",
|
||||||
|
envValue: "",
|
||||||
|
options: []Option{},
|
||||||
|
expectedLimit: defaultCardinalityLimit,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Setenv("OTEL_GO_X_CARDINALITY_LIMIT", tc.envValue)
|
||||||
|
c := newConfig(tc.options)
|
||||||
|
assert.Equal(t, tc.expectedLimit, c.cardinalityLimit)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func sample(parent context.Context) context.Context {
|
func sample(parent context.Context) context.Context {
|
||||||
sc := trace.NewSpanContext(trace.SpanContextConfig{
|
sc := trace.NewSpanContext(trace.SpanContextConfig{
|
||||||
TraceID: trace.TraceID{0x01},
|
TraceID: trace.TraceID{0x01},
|
||||||
|
Reference in New Issue
Block a user