Skip to content

Commit 50f0809

Browse files
committed
autoexport: Add a metric producer registry and ability to set producers
Signed-off-by: Goutham <[email protected]>
1 parent 07d8068 commit 50f0809

File tree

5 files changed

+63
-9
lines changed

5 files changed

+63
-9
lines changed

exporters/autoexport/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.21
55
require (
66
github.com/prometheus/client_golang v1.19.0
77
github.com/stretchr/testify v1.9.0
8+
go.opentelemetry.io/contrib/bridges/prometheus v0.50.0
89
go.opentelemetry.io/otel v1.25.0
910
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0
1011
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.25.0

exporters/autoexport/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN
3333
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
3434
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
3535
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
36+
go.opentelemetry.io/contrib/bridges/prometheus v0.50.0 h1:akXN45Sg2oS2NOb2xBL0LKeq/oSyEIvc8CC/7XLaB+4=
37+
go.opentelemetry.io/contrib/bridges/prometheus v0.50.0/go.mod h1:uoFuIBjQ9kWtUv4KbRNq0ExS9BQoWxHrr63JWX/EMb8=
3638
go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k=
3739
go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg=
3840
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0 h1:hDKnobznDpcdTlNzO0S/owRB8tyVr1OoeZZhDoqY+Cs=

exporters/autoexport/metrics.go

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/prometheus/client_golang/prometheus"
1616
"github.com/prometheus/client_golang/prometheus/promhttp"
1717

18+
prometheusbridge "go.opentelemetry.io/contrib/bridges/prometheus"
1819
"go.opentelemetry.io/otel"
1920
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
2021
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
@@ -71,10 +72,24 @@ func RegisterMetricReader(name string, factory func(context.Context) (metric.Rea
7172
must(metricsSignal.registry.store(name, factory))
7273
}
7374

75+
func RegisterMetricProducer(name string, factory func(context.Context) (metric.Producer, error)) {
76+
must(metricsProducers.registry.store(name, factory))
77+
}
78+
7479
var metricsSignal = newSignal[metric.Reader]("OTEL_METRICS_EXPORTER")
80+
var metricsProducers = newProducerRegistry("OTEL_METRICS_PRODUCERS")
7581

7682
func init() {
7783
RegisterMetricReader("otlp", func(ctx context.Context) (metric.Reader, error) {
84+
producer, err := metricsProducers.create(ctx)
85+
if err != nil {
86+
return nil, err
87+
}
88+
readerOpts := []metric.PeriodicReaderOption{}
89+
if producer != nil {
90+
readerOpts = append(readerOpts, metric.WithProducer(producer))
91+
}
92+
7893
proto := os.Getenv(otelExporterOTLPProtoEnvKey)
7994
if proto == "" {
8095
proto = "http/protobuf"
@@ -86,23 +101,32 @@ func init() {
86101
if err != nil {
87102
return nil, err
88103
}
89-
return metric.NewPeriodicReader(r), nil
104+
return metric.NewPeriodicReader(r, readerOpts...), nil
90105
case "http/protobuf":
91106
r, err := otlpmetrichttp.New(ctx)
92107
if err != nil {
93108
return nil, err
94109
}
95-
return metric.NewPeriodicReader(r), nil
110+
return metric.NewPeriodicReader(r, readerOpts...), nil
96111
default:
97112
return nil, errInvalidOTLPProtocol
98113
}
99114
})
100115
RegisterMetricReader("console", func(ctx context.Context) (metric.Reader, error) {
116+
producer, err := metricsProducers.create(ctx)
117+
if err != nil {
118+
return nil, err
119+
}
120+
readerOpts := []metric.PeriodicReaderOption{}
121+
if producer != nil {
122+
readerOpts = append(readerOpts, metric.WithProducer(producer))
123+
}
124+
101125
r, err := stdoutmetric.New()
102126
if err != nil {
103127
return nil, err
104128
}
105-
return metric.NewPeriodicReader(r), nil
129+
return metric.NewPeriodicReader(r, readerOpts...), nil
106130
})
107131
RegisterMetricReader("none", func(ctx context.Context) (metric.Reader, error) {
108132
return newNoopMetricReader(), nil
@@ -148,6 +172,10 @@ func init() {
148172

149173
return readerWithServer{lis.Addr(), reader, &server}, nil
150174
})
175+
176+
RegisterMetricProducer("prometheus", func(ctx context.Context) (metric.Producer, error) {
177+
return prometheusbridge.NewMetricProducer(), nil
178+
})
151179
}
152180

153181
type readerWithServer struct {
@@ -170,3 +198,26 @@ func getenv(key, fallback string) string {
170198
}
171199
return result
172200
}
201+
202+
type producerRegistry struct {
203+
envKey string
204+
registry *registry[metric.Producer]
205+
}
206+
207+
func newProducerRegistry(envKey string) producerRegistry {
208+
return producerRegistry{
209+
envKey: envKey,
210+
registry: &registry[metric.Producer]{
211+
names: make(map[string]func(context.Context) (metric.Producer, error)),
212+
},
213+
}
214+
}
215+
216+
func (pr producerRegistry) create(ctx context.Context) (metric.Producer, error) {
217+
expType := os.Getenv(pr.envKey)
218+
if expType == "" {
219+
return nil, nil
220+
}
221+
222+
return pr.registry.load(ctx, expType)
223+
}

exporters/autoexport/registry.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ type registry[T any] struct {
2121
}
2222

2323
var (
24-
// errUnknownExporter is returned when an unknown exporter name is used in
25-
// the OTEL_*_EXPORTER environment variables.
26-
errUnknownExporter = errors.New("unknown exporter")
24+
// errUnknownExporterProducer is returned when an unknown exporter name is used in
25+
// the OTEL_*_EXPORTER or OTEL_METRICS_PRODUCERS environment variables.
26+
errUnknownExporterProducer = errors.New("unknown exporter or metrics producer")
2727

2828
// errInvalidOTLPProtocol is returned when an invalid protocol is used in
2929
// the OTEL_EXPORTER_OTLP_PROTOCOL environment variable.
@@ -35,15 +35,15 @@ var (
3535

3636
// load returns tries to find the exporter factory with the key and
3737
// then execute the factory, returning the created SpanExporter.
38-
// errUnknownExporter is returned if the registration is missing and the error from
38+
// errUnknownExporterProducer is returned if the registration is missing and the error from
3939
// executing the factory if not nil.
4040
func (r *registry[T]) load(ctx context.Context, key string) (T, error) {
4141
r.mu.Lock()
4242
defer r.mu.Unlock()
4343
factory, ok := r.names[key]
4444
if !ok {
4545
var zero T
46-
return zero, errUnknownExporter
46+
return zero, errUnknownExporterProducer
4747
}
4848
return factory(ctx)
4949
}

exporters/autoexport/registry_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func TestCanStoreExporterFactory(t *testing.T) {
3434
func TestLoadOfUnknownExporterReturnsError(t *testing.T) {
3535
r := newTestRegistry()
3636
exp, err := r.load(context.Background(), "non-existent")
37-
assert.Equal(t, err, errUnknownExporter, "empty registry should hold nothing")
37+
assert.Equal(t, err, errUnknownExporterProducer, "empty registry should hold nothing")
3838
assert.Nil(t, exp, "non-nil exporter returned")
3939
}
4040

0 commit comments

Comments
 (0)