From 0821c078900910fa9e3ca6c6c0af48a73f00c7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Tue, 9 Jan 2024 12:34:58 +0100 Subject: [PATCH] feat(instrumentation): allow passing in any prometheus.Registerer (#369) The prometheus client_go library primarily uses the prometheus.Registerer interface instead of the prometheus.Registry struct for registering metrics. Especially the global default registry is only exposed as the interfaces `prometheus.Registerer` and `prometheus.Gatherer`[0]. Users that want to use the default registry currently need to make a type assertion to get the struct from the exported interface: hcloud.WithInstrumentation(prometheus.DefaultGatherer.(*prometheus.Registry)) This could fail at any point if the library changes the underlying implmentation to a different struct. controller-runtime is another example of an SDK that only exports the registry as the interface. I had to implement the above type assertation to get hcloud-go metrics in cluster-api-provider-hetzner[1]. This will not break any user code, because the struct we currently accept implements the interface we will accept from now on. [0]: https://github.com/prometheus/client_golang/blob/046e3203b61d1b5000b162e210a91975f098d742/prometheus/registry.go#L54-L58 [1]: https://github.com/syself/cluster-api-provider-hetzner/blob/b421af694d62a6b66ecbb7a6db2ea1f78a620179/pkg/services/hcloud/client/client.go#L88-L92 --- hcloud/client.go | 4 ++-- hcloud/internal/instrumentation/metrics.go | 6 +++--- hcloud/metadata/client.go | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hcloud/client.go b/hcloud/client.go index 5be4c7b5..917bb513 100644 --- a/hcloud/client.go +++ b/hcloud/client.go @@ -65,7 +65,7 @@ type Client struct { applicationVersion string userAgent string debugWriter io.Writer - instrumentationRegistry *prometheus.Registry + instrumentationRegistry prometheus.Registerer Action ActionClient Certificate CertificateClient @@ -163,7 +163,7 @@ func WithHTTPClient(httpClient *http.Client) ClientOption { } // WithInstrumentation configures a Client to collect metrics about the performed HTTP requests. -func WithInstrumentation(registry *prometheus.Registry) ClientOption { +func WithInstrumentation(registry prometheus.Registerer) ClientOption { return func(client *Client) { client.instrumentationRegistry = registry } diff --git a/hcloud/internal/instrumentation/metrics.go b/hcloud/internal/instrumentation/metrics.go index aa57c710..e52bd606 100644 --- a/hcloud/internal/instrumentation/metrics.go +++ b/hcloud/internal/instrumentation/metrics.go @@ -13,11 +13,11 @@ import ( type Instrumenter struct { subsystemIdentifier string // will be used as part of the metric name (hcloud__requests_total) - instrumentationRegistry *prometheus.Registry + instrumentationRegistry prometheus.Registerer } // New creates a new Instrumenter. The subsystemIdentifier will be used as part of the metric names (e.g. hcloud__requests_total). -func New(subsystemIdentifier string, instrumentationRegistry *prometheus.Registry) *Instrumenter { +func New(subsystemIdentifier string, instrumentationRegistry prometheus.Registerer) *Instrumenter { return &Instrumenter{subsystemIdentifier: subsystemIdentifier, instrumentationRegistry: instrumentationRegistry} } @@ -84,7 +84,7 @@ func (i *Instrumenter) instrumentRoundTripperEndpoint(counter *prometheus.Counte // registerOrReuse will try to register the passed Collector, but in case a conflicting collector was already registered, // it will instead return that collector. Make sure to always use the collector return by this method. // Similar to [Registry.MustRegister] it will panic if any other error occurs. -func registerOrReuse[C prometheus.Collector](registry *prometheus.Registry, collector C) C { +func registerOrReuse[C prometheus.Collector](registry prometheus.Registerer, collector C) C { err := registry.Register(collector) if err != nil { // If we get a AlreadyRegisteredError we can return the existing collector diff --git a/hcloud/metadata/client.go b/hcloud/metadata/client.go index aa796d27..f9634c36 100644 --- a/hcloud/metadata/client.go +++ b/hcloud/metadata/client.go @@ -22,7 +22,7 @@ type Client struct { timeout time.Duration httpClient *http.Client - instrumentationRegistry *prometheus.Registry + instrumentationRegistry prometheus.Registerer } // A ClientOption is used to configure a [Client]. @@ -43,7 +43,7 @@ func WithHTTPClient(httpClient *http.Client) ClientOption { } // WithInstrumentation configures a [Client] to collect metrics about the performed HTTP requests. -func WithInstrumentation(registry *prometheus.Registry) ClientOption { +func WithInstrumentation(registry prometheus.Registerer) ClientOption { return func(client *Client) { client.instrumentationRegistry = registry }