Skip to content

Commit 9389c19

Browse files
committed
Add fallback metric producer factory
Signed-off-by: gouthamve <[email protected]>
1 parent 703930c commit 9389c19

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

exporters/autoexport/metrics.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ func RegisterMetricProducer(name string, factory func(context.Context) (metric.P
7979
must(metricsProducers.registry.store(name, factory))
8080
}
8181

82+
// WithFallbackMetricProducer sets the fallback producer to use when no producer
83+
// is configured through the OTEL_METRICS_PRODUCERS environment variable.
84+
func WithFallbackMetricProducer(producerFactory func(ctx context.Context) (metric.Producer, error)) {
85+
metricsProducers.fallbackProducer = producerFactory
86+
}
87+
8288
var (
8389
metricsSignal = newSignal[metric.Reader]("OTEL_METRICS_EXPORTER")
8490
metricsProducers = newProducerRegistry("OTEL_METRICS_PRODUCERS")
@@ -217,8 +223,9 @@ func getenv(key, fallback string) string {
217223
}
218224

219225
type producerRegistry struct {
220-
envKey string
221-
registry *registry[metric.Producer]
226+
envKey string
227+
fallbackProducer func(context.Context) (metric.Producer, error)
228+
registry *registry[metric.Producer]
222229
}
223230

224231
func newProducerRegistry(envKey string) producerRegistry {
@@ -233,6 +240,10 @@ func newProducerRegistry(envKey string) producerRegistry {
233240
func (pr producerRegistry) create(ctx context.Context) (metric.Producer, error) {
234241
expType := os.Getenv(pr.envKey)
235242
if expType == "" {
243+
if pr.fallbackProducer != nil {
244+
return pr.fallbackProducer(ctx)
245+
}
246+
236247
return nil, nil
237248
}
238249

exporters/autoexport/metrics_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ import (
1515
"testing"
1616

1717
"go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp"
18+
prometheusbridge "go.opentelemetry.io/contrib/bridges/prometheus"
1819
"go.opentelemetry.io/otel"
1920
"go.opentelemetry.io/otel/sdk/metric"
2021

22+
"github.com/prometheus/client_golang/prometheus"
2123
"github.com/stretchr/testify/assert"
2224
"go.uber.org/goleak"
2325
)
@@ -192,3 +194,42 @@ func TestMetricProducerPrometheusWithPrometheusExporter(t *testing.T) {
192194
assert.NoError(t, mp.Shutdown(context.Background()))
193195
goleak.VerifyNone(t)
194196
}
197+
198+
func TestMetricProducerFallbackWithPrometheusExporter(t *testing.T) {
199+
assertNoOtelHandleErrors(t)
200+
201+
reg := prometheus.NewRegistry()
202+
someDummyMetric := prometheus.NewCounter(prometheus.CounterOpts{
203+
Name: "dummy_metric",
204+
Help: "dummy metric",
205+
})
206+
reg.MustRegister(someDummyMetric)
207+
208+
WithFallbackMetricProducer(func(context.Context) (metric.Producer, error) {
209+
return prometheusbridge.NewMetricProducer(prometheusbridge.WithGatherer(reg)), nil
210+
})
211+
212+
t.Setenv("OTEL_METRICS_EXPORTER", "prometheus")
213+
t.Setenv("OTEL_EXPORTER_PROMETHEUS_PORT", "0")
214+
215+
r, err := NewMetricReader(context.Background())
216+
assert.NoError(t, err)
217+
218+
// pull-based exporters like Prometheus need to be registered
219+
mp := metric.NewMeterProvider(metric.WithReader(r))
220+
221+
rws, ok := r.(readerWithServer)
222+
if !ok {
223+
t.Errorf("expected readerWithServer but got %v", r)
224+
}
225+
226+
resp, err := http.Get(fmt.Sprintf("http://%s/metrics", rws.addr))
227+
assert.NoError(t, err)
228+
body, err := io.ReadAll(resp.Body)
229+
assert.NoError(t, err)
230+
231+
assert.Contains(t, string(body), "HELP dummy_metric_total dummy metric")
232+
233+
assert.NoError(t, mp.Shutdown(context.Background()))
234+
goleak.VerifyNone(t)
235+
}

0 commit comments

Comments
 (0)