You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-11-29 23:07:45 +02:00
Allow configuring the exemplar filter on the metrics SDK (#5850)
Part of https://github.com/open-telemetry/opentelemetry-go/issues/5249 ### Spec https://opentelemetry.io/docs/specs/otel/metrics/sdk/#exemplarfilter > The ExemplarFilter configuration MUST allow users to select between one of the built-in ExemplarFilters. While ExemplarFilter determines which measurements are eligible for becoming an Exemplar, the ExemplarReservoir makes the final decision if a measurement becomes an exemplar and is stored. > The ExemplarFilter SHOULD be a configuration parameter of a MeterProvider for an SDK. The default value SHOULD be TraceBased. The filter configuration SHOULD follow the [environment variable specification](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#exemplar). > An OpenTelemetry SDK MUST support the following filters: > * [AlwaysOn](https://opentelemetry.io/docs/specs/otel/metrics/sdk/#alwayson) > * [AlwaysOff](https://opentelemetry.io/docs/specs/otel/metrics/sdk/#alwaysoff) > * [TraceBased](https://opentelemetry.io/docs/specs/otel/metrics/sdk/#tracebased) ### Changes * adds exemplar.AlwaysOffFilter, which is one of the required filters from the SDK: https://opentelemetry.io/docs/specs/otel/metrics/sdk/#alwaysoff * adds `metric.WithExemplarFilter` as an option for the metrics SDK. * moves handling of `OTEL_METRICS_EXEMPLAR_FILTER` to the same location as config handling to make code easier to navigate. dropReservoir can actually be removed, but I plan to do that in a follow-up refactor, since it will be a large diff. --------- Co-authored-by: Damien Mathieu <42@dmathieu.com> Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com> Co-authored-by: Chester Cheung <cheung.zhy.csu@gmail.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/sdk/metric/exemplar"
|
||||
"go.opentelemetry.io/otel/sdk/metric/internal/aggregate"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metricdata"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest"
|
||||
@@ -357,7 +358,7 @@ func testCreateAggregators[N int64 | float64](t *testing.T) {
|
||||
for _, tt := range testcases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var c cache[string, instID]
|
||||
p := newPipeline(nil, tt.reader, tt.views)
|
||||
p := newPipeline(nil, tt.reader, tt.views, exemplar.AlwaysOffFilter)
|
||||
i := newInserter[N](p, &c)
|
||||
readerAggregation := i.readerDefaultAggregation(tt.inst.Kind)
|
||||
input, err := i.Instrument(tt.inst, readerAggregation)
|
||||
@@ -379,7 +380,7 @@ func TestCreateAggregators(t *testing.T) {
|
||||
|
||||
func testInvalidInstrumentShouldPanic[N int64 | float64]() {
|
||||
var c cache[string, instID]
|
||||
i := newInserter[N](newPipeline(nil, NewManualReader(), []View{defaultView}), &c)
|
||||
i := newInserter[N](newPipeline(nil, NewManualReader(), []View{defaultView}, exemplar.AlwaysOffFilter), &c)
|
||||
inst := Instrument{
|
||||
Name: "foo",
|
||||
Kind: InstrumentKind(255),
|
||||
@@ -395,7 +396,7 @@ func TestInvalidInstrumentShouldPanic(t *testing.T) {
|
||||
|
||||
func TestPipelinesAggregatorForEachReader(t *testing.T) {
|
||||
r0, r1 := NewManualReader(), NewManualReader()
|
||||
pipes := newPipelines(resource.Empty(), []Reader{r0, r1}, nil)
|
||||
pipes := newPipelines(resource.Empty(), []Reader{r0, r1}, nil, exemplar.AlwaysOffFilter)
|
||||
require.Len(t, pipes, 2, "created pipelines")
|
||||
|
||||
inst := Instrument{Name: "foo", Kind: InstrumentKindCounter}
|
||||
@@ -467,7 +468,7 @@ func TestPipelineRegistryCreateAggregators(t *testing.T) {
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
p := newPipelines(resource.Empty(), tt.readers, tt.views)
|
||||
p := newPipelines(resource.Empty(), tt.readers, tt.views, exemplar.AlwaysOffFilter)
|
||||
testPipelineRegistryResolveIntAggregators(t, p, tt.wantCount)
|
||||
testPipelineRegistryResolveFloatAggregators(t, p, tt.wantCount)
|
||||
testPipelineRegistryResolveIntHistogramAggregators(t, p, tt.wantCount)
|
||||
@@ -521,7 +522,7 @@ func TestPipelineRegistryResource(t *testing.T) {
|
||||
readers := []Reader{NewManualReader()}
|
||||
views := []View{defaultView, v}
|
||||
res := resource.NewSchemaless(attribute.String("key", "val"))
|
||||
pipes := newPipelines(res, readers, views)
|
||||
pipes := newPipelines(res, readers, views, exemplar.AlwaysOffFilter)
|
||||
for _, p := range pipes {
|
||||
assert.True(t, res.Equal(p.resource), "resource not set")
|
||||
}
|
||||
@@ -532,7 +533,7 @@ func TestPipelineRegistryCreateAggregatorsIncompatibleInstrument(t *testing.T) {
|
||||
|
||||
readers := []Reader{testRdrHistogram}
|
||||
views := []View{defaultView}
|
||||
p := newPipelines(resource.Empty(), readers, views)
|
||||
p := newPipelines(resource.Empty(), readers, views, exemplar.AlwaysOffFilter)
|
||||
inst := Instrument{Name: "foo", Kind: InstrumentKindObservableGauge}
|
||||
|
||||
var vc cache[string, instID]
|
||||
@@ -592,7 +593,7 @@ func TestResolveAggregatorsDuplicateErrors(t *testing.T) {
|
||||
fooInst := Instrument{Name: "foo", Kind: InstrumentKindCounter}
|
||||
barInst := Instrument{Name: "bar", Kind: InstrumentKindCounter}
|
||||
|
||||
p := newPipelines(resource.Empty(), readers, views)
|
||||
p := newPipelines(resource.Empty(), readers, views, exemplar.AlwaysOffFilter)
|
||||
|
||||
var vc cache[string, instID]
|
||||
ri := newResolver[int64](p, &vc)
|
||||
|
||||
Reference in New Issue
Block a user