Skip to content

Commit

Permalink
Add fallback metric producer factory
Browse files Browse the repository at this point in the history
Signed-off-by: gouthamve <[email protected]>
  • Loading branch information
gouthamve committed Apr 14, 2024
1 parent 703930c commit 9389c19
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 2 deletions.
15 changes: 13 additions & 2 deletions exporters/autoexport/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ func RegisterMetricProducer(name string, factory func(context.Context) (metric.P
must(metricsProducers.registry.store(name, factory))
}

// WithFallbackMetricProducer sets the fallback producer to use when no producer
// is configured through the OTEL_METRICS_PRODUCERS environment variable.
func WithFallbackMetricProducer(producerFactory func(ctx context.Context) (metric.Producer, error)) {
metricsProducers.fallbackProducer = producerFactory
}

var (
metricsSignal = newSignal[metric.Reader]("OTEL_METRICS_EXPORTER")
metricsProducers = newProducerRegistry("OTEL_METRICS_PRODUCERS")
Expand Down Expand Up @@ -217,8 +223,9 @@ func getenv(key, fallback string) string {
}

type producerRegistry struct {
envKey string
registry *registry[metric.Producer]
envKey string
fallbackProducer func(context.Context) (metric.Producer, error)
registry *registry[metric.Producer]
}

func newProducerRegistry(envKey string) producerRegistry {
Expand All @@ -233,6 +240,10 @@ func newProducerRegistry(envKey string) producerRegistry {
func (pr producerRegistry) create(ctx context.Context) (metric.Producer, error) {
expType := os.Getenv(pr.envKey)
if expType == "" {
if pr.fallbackProducer != nil {
return pr.fallbackProducer(ctx)
}

return nil, nil
}

Expand Down
41 changes: 41 additions & 0 deletions exporters/autoexport/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import (
"testing"

"go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp"
prometheusbridge "go.opentelemetry.io/contrib/bridges/prometheus"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/sdk/metric"

"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"
"go.uber.org/goleak"
)
Expand Down Expand Up @@ -192,3 +194,42 @@ func TestMetricProducerPrometheusWithPrometheusExporter(t *testing.T) {
assert.NoError(t, mp.Shutdown(context.Background()))
goleak.VerifyNone(t)
}

func TestMetricProducerFallbackWithPrometheusExporter(t *testing.T) {
assertNoOtelHandleErrors(t)

reg := prometheus.NewRegistry()
someDummyMetric := prometheus.NewCounter(prometheus.CounterOpts{
Name: "dummy_metric",
Help: "dummy metric",
})
reg.MustRegister(someDummyMetric)

WithFallbackMetricProducer(func(context.Context) (metric.Producer, error) {
return prometheusbridge.NewMetricProducer(prometheusbridge.WithGatherer(reg)), nil
})

t.Setenv("OTEL_METRICS_EXPORTER", "prometheus")
t.Setenv("OTEL_EXPORTER_PROMETHEUS_PORT", "0")

r, err := NewMetricReader(context.Background())
assert.NoError(t, err)

// pull-based exporters like Prometheus need to be registered
mp := metric.NewMeterProvider(metric.WithReader(r))

rws, ok := r.(readerWithServer)
if !ok {
t.Errorf("expected readerWithServer but got %v", r)
}

resp, err := http.Get(fmt.Sprintf("http://%s/metrics", rws.addr))
assert.NoError(t, err)
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err)

assert.Contains(t, string(body), "HELP dummy_metric_total dummy metric")

assert.NoError(t, mp.Shutdown(context.Background()))
goleak.VerifyNone(t)
}

0 comments on commit 9389c19

Please sign in to comment.