diff --git a/scrape/manager.go b/scrape/manager.go index 3ad315a50..e805fd43a 100644 --- a/scrape/manager.go +++ b/scrape/manager.go @@ -129,6 +129,11 @@ func (m *Manager) Run(tsets <-chan map[string][]*targetgroup.Group) error { } } +// UnregisterMetrics unregisters manager metrics. +func (m *Manager) UnregisterMetrics() { + m.metrics.Unregister() +} + func (m *Manager) reloader() { reloadIntervalDuration := m.opts.DiscoveryReloadInterval if reloadIntervalDuration < model.Duration(5*time.Second) { diff --git a/scrape/manager_test.go b/scrape/manager_test.go index f90fd0ce6..51af45f8c 100644 --- a/scrape/manager_test.go +++ b/scrape/manager_test.go @@ -857,3 +857,16 @@ func getResultFloats(app *collectResultAppender, expectedMetricName string) (res } return result } + +func TestUnregisterMetrics(t *testing.T) { + reg := prometheus.NewRegistry() + // Check that all metrics can be unregistered, allowing a second manager to be created. + for i := 0; i < 2; i++ { + opts := Options{} + manager, err := NewManager(&opts, nil, nil, reg) + require.NotNil(t, manager) + require.NoError(t, err) + // Unregister all metrics. + manager.UnregisterMetrics() + } +} diff --git a/scrape/metrics.go b/scrape/metrics.go index 7082bc743..b67d0686b 100644 --- a/scrape/metrics.go +++ b/scrape/metrics.go @@ -20,6 +20,7 @@ import ( ) type scrapeMetrics struct { + reg prometheus.Registerer // Used by Manager. targetMetadataCache *MetadataMetricsCollector targetScrapePools prometheus.Counter @@ -54,7 +55,7 @@ type scrapeMetrics struct { } func newScrapeMetrics(reg prometheus.Registerer) (*scrapeMetrics, error) { - sm := &scrapeMetrics{} + sm := &scrapeMetrics{reg: reg} // Manager metrics. sm.targetMetadataCache = &MetadataMetricsCollector{ @@ -260,6 +261,32 @@ func (sm *scrapeMetrics) setTargetMetadataCacheGatherer(gatherer TargetsGatherer sm.targetMetadataCache.TargetsGatherer = gatherer } +// Unregister unregisters all metrics. +func (sm *scrapeMetrics) Unregister() { + sm.reg.Unregister(sm.targetMetadataCache) + sm.reg.Unregister(sm.targetScrapePools) + sm.reg.Unregister(sm.targetScrapePoolsFailed) + sm.reg.Unregister(sm.targetReloadIntervalLength) + sm.reg.Unregister(sm.targetScrapePoolReloads) + sm.reg.Unregister(sm.targetScrapePoolReloadsFailed) + sm.reg.Unregister(sm.targetSyncIntervalLength) + sm.reg.Unregister(sm.targetScrapePoolSyncsCounter) + sm.reg.Unregister(sm.targetScrapePoolExceededTargetLimit) + sm.reg.Unregister(sm.targetScrapePoolTargetLimit) + sm.reg.Unregister(sm.targetScrapePoolTargetsAdded) + sm.reg.Unregister(sm.targetSyncFailed) + sm.reg.Unregister(sm.targetScrapeExceededBodySizeLimit) + sm.reg.Unregister(sm.targetScrapeCacheFlushForced) + sm.reg.Unregister(sm.targetIntervalLength) + sm.reg.Unregister(sm.targetScrapeSampleLimit) + sm.reg.Unregister(sm.targetScrapeSampleDuplicate) + sm.reg.Unregister(sm.targetScrapeSampleOutOfOrder) + sm.reg.Unregister(sm.targetScrapeSampleOutOfBounds) + sm.reg.Unregister(sm.targetScrapeExemplarOutOfOrder) + sm.reg.Unregister(sm.targetScrapePoolExceededLabelLimits) + sm.reg.Unregister(sm.targetScrapeNativeHistogramBucketLimit) +} + type TargetsGatherer interface { TargetsActive() map[string][]*Target }