From ada8bd0803eb9171b8ba46060d1f9478aeb73ac9 Mon Sep 17 00:00:00 2001 From: Jignesh Atul Paratane Date: Wed, 18 Feb 2026 22:41:37 +0530 Subject: [PATCH 1/7] Added a directory collector, and a code file collector.go in which the collector will be defined, right now only the client interface and struct is defined. #5 --- internal/collector/redfish_collector.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 internal/collector/redfish_collector.go diff --git a/internal/collector/redfish_collector.go b/internal/collector/redfish_collector.go new file mode 100644 index 0000000..c96e2b2 --- /dev/null +++ b/internal/collector/redfish_collector.go @@ -0,0 +1,15 @@ +package collector + +import "github.com/prometheus/client_golang/prometheus" + +type RedfishAPI interface { + Get(endpoint string, target interface{}) (int, error) +} + +type RedfishCollector struct { + client RedfishAPI + + powerConsumedDesc *prometheus.Desc + powerCapacityDesc *prometheus.Desc + redfishUpDesc *prometheus.Desc +} From 9c4a2c2a3044595ee4019972970770be7e325145 Mon Sep 17 00:00:00 2001 From: Jignesh Atul Paratane Date: Wed, 18 Feb 2026 22:51:16 +0530 Subject: [PATCH 2/7] Added a Describe() method standard to Collector interface, and created a new constructor to initialize metrics. #5 --- internal/collector/redfish_collector.go | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/internal/collector/redfish_collector.go b/internal/collector/redfish_collector.go index c96e2b2..55afd05 100644 --- a/internal/collector/redfish_collector.go +++ b/internal/collector/redfish_collector.go @@ -13,3 +13,36 @@ type RedfishCollector struct { powerCapacityDesc *prometheus.Desc redfishUpDesc *prometheus.Desc } + +func NewRedfishCollector(client RedfishAPI) *RedfishCollector { + return &RedfishCollector{ + client: client, + powerConsumedDesc: prometheus.NewDesc( + "power_consumed_watts", + "Current PSU power consumption in watts", + nil, + nil, + ), + + powerCapacityDesc: prometheus.NewDesc( + "power_capacity_watts", + "PSU power capacity in watts", + nil, + nil, + ), + + redfishUpDesc: prometheus.NewDesc( + "redfish_up", + "Redfish API Response Status (1 = up, 0 = down)", + nil, + nil, + ), + } +} + +func (c *RedfishCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- c.powerConsumedDesc + ch <- c.powerCapacityDesc + ch <- c.redfishUpDesc +} + From 5eaed1581f374ace53d5367af6a938e7f5897dce Mon Sep 17 00:00:00 2001 From: Jignesh Atul Paratane Date: Wed, 18 Feb 2026 23:07:16 +0530 Subject: [PATCH 3/7] Added the Collect() method implementing the collector interface. Added some trivial metrics to be tested for robustness and reliability. #5 --- internal/collector/redfish_collector.go | 56 ++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/internal/collector/redfish_collector.go b/internal/collector/redfish_collector.go index 55afd05..8197ac7 100644 --- a/internal/collector/redfish_collector.go +++ b/internal/collector/redfish_collector.go @@ -1,6 +1,11 @@ package collector -import "github.com/prometheus/client_golang/prometheus" +import ( + "goprom/internal/models" + "net/http" + + "github.com/prometheus/client_golang/prometheus" +) type RedfishAPI interface { Get(endpoint string, target interface{}) (int, error) @@ -46,3 +51,52 @@ func (c *RedfishCollector) Describe(ch chan<- *prometheus.Desc) { ch <- c.redfishUpDesc } +func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { + + var power models.PowerControl + status, err := c.client.Get("/redfish/v1/Chassis/System.Embedded.1/Power", &power) + if err != nil { + ch <- prometheus.MustNewConstMetric( + c.redfishUpDesc, + prometheus.GaugeValue, + 0, + ) + return + } + + if status == http.StatusNotFound { + ch <- prometheus.MustNewConstMetric( + c.redfishUpDesc, + prometheus.GaugeValue, + 1, + ) + return + } + + if status != http.StatusOK { + ch <- prometheus.MustNewConstMetric( + c.redfishUpDesc, + prometheus.GaugeValue, + 0, + ) + return + } + + ch <- prometheus.MustNewConstMetric( + c.powerConsumedDesc, + prometheus.GaugeValue, + float64(power.PowerConsumedWatts), + ) + + ch <- prometheus.MustNewConstMetric( + c.powerCapacityDesc, + prometheus.GaugeValue, + float64(power.PowerCapacityWatts), + ) + + ch <- prometheus.MustNewConstMetric( + c.redfishUpDesc, + prometheus.GaugeValue, + 1, + ) +} From e856c636eb7d76f14c2756866fa4348ff68b0626 Mon Sep 17 00:00:00 2001 From: Jignesh Atul Paratane Date: Thu, 19 Feb 2026 14:11:00 +0530 Subject: [PATCH 4/7] Fixed the endpoint url, to fix the 0 value return at scrape time issue. #5 --- internal/collector/redfish_collector.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/collector/redfish_collector.go b/internal/collector/redfish_collector.go index 8197ac7..398978a 100644 --- a/internal/collector/redfish_collector.go +++ b/internal/collector/redfish_collector.go @@ -54,7 +54,7 @@ func (c *RedfishCollector) Describe(ch chan<- *prometheus.Desc) { func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { var power models.PowerControl - status, err := c.client.Get("/redfish/v1/Chassis/System.Embedded.1/Power", &power) + status, err := c.client.Get("/redfish/v1/Chassis/System.Embedded.1/Power/PowerControl", &power) if err != nil { ch <- prometheus.MustNewConstMetric( c.redfishUpDesc, From b373a4c04231637bd402bca3094213283035de5b Mon Sep 17 00:00:00 2001 From: Jignesh Atul Paratane Date: Thu, 19 Feb 2026 14:12:25 +0530 Subject: [PATCH 5/7] Commented out the legacy Ticker Method based calling and replaced with Collector based calling. #5 --- cmd/exporter/main.go | 110 +++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 51 deletions(-) diff --git a/cmd/exporter/main.go b/cmd/exporter/main.go index 052c7f8..288428c 100644 --- a/cmd/exporter/main.go +++ b/cmd/exporter/main.go @@ -1,70 +1,78 @@ package main import ( - "goprom/internal/metrics" + "goprom/internal/collector" "goprom/internal/redfish" "log" "net/http" - "time" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { - metrics.InitMetrics() - metrics.InitTemperatureMetrics() - go func() { - //time.Sleep(20 * time.Second) - ticker := time.NewTicker(60 * time.Second) - defer ticker.Stop() + // metrics.InitMetrics() + // metrics.InitTemperatureMetrics() + // go func() { + // //time.Sleep(20 * time.Second) + // ticker := time.NewTicker(60 * time.Second) + // defer ticker.Stop() - fetch := func() { - power, err := redfish.RetrievePowerValues() - if err != nil { - log.Printf("Error retrieving power values: %v", err) - metrics.UpdateHealth(false) - return - } - metrics.UpdateHealth(true) - metrics.UpdateMetrics(power) - } + // fetch := func() { + // power, err := redfish.RetrievePowerValues() + // if err != nil { + // log.Printf("Error retrieving power values: %v", err) + // metrics.UpdateHealth(false) + // return + // } + // metrics.UpdateHealth(true) + // metrics.UpdateMetrics(power) + // } - fetch2 := func() { - temperature, err := redfish.RetrieveTemperatureValues() - if err != nil { - log.Printf("Error retrieving temperature values: %v", err) - metrics.UpdateHealth(false) - return - } - metrics.UpdateTemperatureMetrics(temperature) - } + // fetch2 := func() { + // temperature, err := redfish.RetrieveTemperatureValues() + // if err != nil { + // log.Printf("Error retrieving temperature values: %v", err) + // metrics.UpdateHealth(false) + // return + // } + // metrics.UpdateTemperatureMetrics(temperature) + // } - fetch3 := func() { - client := redfish.NewClient( - redfish.BaseURL, - "root", - "calvin", - ) + // fetch3 := func() { + // client := redfish.NewClient( + // redfish.BaseURL, + // "root", + // "calvin", + // ) - temps, err := client.GetTemperatures(redfish.Temperature_Endpoints) - if err != nil { - log.Printf("Error retrieving temperature values: %v", err) - return - } + // temps, err := client.GetTemperatures(redfish.Temperature_Endpoints) + // if err != nil { + // log.Printf("Error retrieving temperature values: %v", err) + // return + // } - for _, t := range temps { - metrics.UpdateTemperatureMetrics(t) - } - } - fetch() - fetch2() - fetch3() - for range ticker.C { - fetch() - fetch2() - fetch3() - } - }() + // for _, t := range temps { + // metrics.UpdateTemperatureMetrics(t) + // } + // } + // fetch() + // fetch2() + // fetch3() + // for range ticker.C { + // fetch() + // fetch2() + // fetch3() + // } + // }() + + rfCollector := collector.NewRedfishCollector(redfish.NewClient( + redfish.BaseURL, + "root", + "calvin", + )) + + prometheus.MustRegister(rfCollector) http.Handle("/metrics", promhttp.Handler()) From 4c2427c275a2a3d2fbf13c165ba0ee2b52d3bf98 Mon Sep 17 00:00:00 2001 From: Jignesh Atul Paratane Date: Thu, 19 Feb 2026 14:36:23 +0530 Subject: [PATCH 6/7] Implemented the collector interface and emitting of temperature metrics. #5 --- internal/collector/redfish_collector.go | 250 ++++++++++++++++++++---- 1 file changed, 215 insertions(+), 35 deletions(-) diff --git a/internal/collector/redfish_collector.go b/internal/collector/redfish_collector.go index 398978a..ae2631a 100644 --- a/internal/collector/redfish_collector.go +++ b/internal/collector/redfish_collector.go @@ -2,7 +2,10 @@ package collector import ( "goprom/internal/models" + "goprom/internal/redfish" "net/http" + "strconv" + "time" "github.com/prometheus/client_golang/prometheus" ) @@ -14,89 +17,266 @@ type RedfishAPI interface { type RedfishCollector struct { client RedfishAPI + // Power powerConsumedDesc *prometheus.Desc powerCapacityDesc *prometheus.Desc - redfishUpDesc *prometheus.Desc + + // Health + redfishUpDesc *prometheus.Desc + scrapeDurationDesc *prometheus.Desc + + // Temperature metrics + readingCelsiusDesc *prometheus.Desc + lowerThresholdCriticalDesc *prometheus.Desc + lowerThresholdFatalDesc *prometheus.Desc + upperThresholdCriticalDesc *prometheus.Desc + upperThresholdFatalDesc *prometheus.Desc + lowerThresholdNonCriticalDesc *prometheus.Desc + upperThresholdNonCriticalDesc *prometheus.Desc } func NewRedfishCollector(client RedfishAPI) *RedfishCollector { return &RedfishCollector{ client: client, + + // Power powerConsumedDesc: prometheus.NewDesc( - "power_consumed_watts", + "redfish_power_consumed_watts", "Current PSU power consumption in watts", nil, nil, ), powerCapacityDesc: prometheus.NewDesc( - "power_capacity_watts", + "redfish_power_capacity_watts", "PSU power capacity in watts", nil, nil, ), + // Overall health redfishUpDesc: prometheus.NewDesc( "redfish_up", - "Redfish API Response Status (1 = up, 0 = down)", + "Overall Redfish scrape status (1 = success, 0 = failure)", + nil, + nil, + ), + + scrapeDurationDesc: prometheus.NewDesc( + "redfish_scrape_duration_seconds", + "Time taken to scrape Redfish in seconds", nil, nil, ), + + // Temperature metrics + readingCelsiusDesc: prometheus.NewDesc( + "redfish_temperature_reading_celsius", + "Current temperature reading", + []string{"name", "physical_context", "sensor_number"}, + nil, + ), + + lowerThresholdCriticalDesc: prometheus.NewDesc( + "redfish_temperature_lower_threshold_critical", + "Lower critical temperature threshold", + []string{"name", "physical_context", "sensor_number"}, + nil, + ), + + lowerThresholdFatalDesc: prometheus.NewDesc( + "redfish_temperature_lower_threshold_fatal", + "Lower fatal temperature threshold", + []string{"name", "physical_context", "sensor_number"}, + nil, + ), + + upperThresholdCriticalDesc: prometheus.NewDesc( + "redfish_temperature_upper_threshold_critical", + "Upper critical temperature threshold", + []string{"name", "physical_context", "sensor_number"}, + nil, + ), + + upperThresholdFatalDesc: prometheus.NewDesc( + "redfish_temperature_upper_threshold_fatal", + "Upper fatal temperature threshold", + []string{"name", "physical_context", "sensor_number"}, + nil, + ), + + lowerThresholdNonCriticalDesc: prometheus.NewDesc( + "redfish_temperature_lower_threshold_non_critical", + "Lower non-critical temperature threshold", + []string{"name", "physical_context", "sensor_number"}, + nil, + ), + + upperThresholdNonCriticalDesc: prometheus.NewDesc( + "redfish_temperature_upper_threshold_non_critical", + "Upper non-critical temperature threshold", + []string{"name", "physical_context", "sensor_number"}, + nil, + ), } } func (c *RedfishCollector) Describe(ch chan<- *prometheus.Desc) { + // Power ch <- c.powerConsumedDesc ch <- c.powerCapacityDesc + + // Health ch <- c.redfishUpDesc + ch <- c.scrapeDurationDesc + + // Temperature + ch <- c.readingCelsiusDesc + ch <- c.lowerThresholdCriticalDesc + ch <- c.lowerThresholdFatalDesc + ch <- c.upperThresholdCriticalDesc + ch <- c.upperThresholdFatalDesc + ch <- c.lowerThresholdNonCriticalDesc + ch <- c.upperThresholdNonCriticalDesc } func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { + start := time.Now() + overallSuccess := true + //------------------------------------- + // 1. POWER ENDPOINT + //------------------------------------- var power models.PowerControl - status, err := c.client.Get("/redfish/v1/Chassis/System.Embedded.1/Power/PowerControl", &power) - if err != nil { - ch <- prometheus.MustNewConstMetric( - c.redfishUpDesc, - prometheus.GaugeValue, - 0, - ) - return - } + status, err := c.client.Get(redfish.Power_Endpoints[0], &power) - if status == http.StatusNotFound { + if err != nil || (status != http.StatusOK && status != http.StatusNotFound) { + overallSuccess = false + } else if status == http.StatusOK { ch <- prometheus.MustNewConstMetric( - c.redfishUpDesc, + c.powerConsumedDesc, prometheus.GaugeValue, - 1, + float64(power.PowerConsumedWatts), ) - return - } - - if status != http.StatusOK { ch <- prometheus.MustNewConstMetric( - c.redfishUpDesc, + c.powerCapacityDesc, prometheus.GaugeValue, - 0, + float64(power.PowerCapacityWatts), ) - return } - ch <- prometheus.MustNewConstMetric( - c.powerConsumedDesc, - prometheus.GaugeValue, - float64(power.PowerConsumedWatts), - ) + //------------------------------------- + // 2. TEMPERATURE ENDPOINTS + //------------------------------------- + for _, endpoint := range redfish.Temperature_Endpoints { + var t models.Temperature + status, err := c.client.Get(endpoint, &t) - ch <- prometheus.MustNewConstMetric( - c.powerCapacityDesc, - prometheus.GaugeValue, - float64(power.PowerCapacityWatts), - ) + if err != nil { + overallSuccess = false + continue + } + if status == http.StatusNotFound { + continue + } + if status != http.StatusOK { + overallSuccess = false + continue + } + + // Labels + labels := []string{t.Name, t.PhysicalContext, strconv.Itoa(t.SensorNumber)} + + //------------------------------------- + // Emit temperature metrics + //------------------------------------- + if t.ReadingCelsius != nil { + ch <- prometheus.MustNewConstMetric( + c.readingCelsiusDesc, + prometheus.GaugeValue, + float64(*t.ReadingCelsius), + labels..., + ) + } + // ---- SAFE THRESHOLD EMITS ---- + + // Lower Critical + if t.LowerThresholdCritical != nil { + ch <- prometheus.MustNewConstMetric( + c.lowerThresholdCriticalDesc, + prometheus.GaugeValue, + float64(*t.LowerThresholdCritical), + labels..., + ) + } + + // Lower Fatal + if t.LowerThresholdFatal != nil { + ch <- prometheus.MustNewConstMetric( + c.lowerThresholdFatalDesc, + prometheus.GaugeValue, + float64(*t.LowerThresholdFatal), + labels..., + ) + } + + // Upper Critical + if t.UpperThresholdCritical != nil { + ch <- prometheus.MustNewConstMetric( + c.upperThresholdCriticalDesc, + prometheus.GaugeValue, + float64(*t.UpperThresholdCritical), + labels..., + ) + } + + // Upper Fatal + if t.UpperThresholdFatal != nil { + ch <- prometheus.MustNewConstMetric( + c.upperThresholdFatalDesc, + prometheus.GaugeValue, + float64(*t.UpperThresholdFatal), + labels..., + ) + } + + // Lower Non-Critical + if t.LowerThresholdNonCritical != nil { + ch <- prometheus.MustNewConstMetric( + c.lowerThresholdNonCriticalDesc, + prometheus.GaugeValue, + float64(*t.LowerThresholdNonCritical), + labels..., + ) + } + + // Upper Non-Critical + if t.UpperThresholdNonCritical != nil { + ch <- prometheus.MustNewConstMetric( + c.upperThresholdNonCriticalDesc, + prometheus.GaugeValue, + float64(*t.UpperThresholdNonCritical), + labels..., + ) + } + } + + //------------------------------------- + // 3. EXPORTER HEALTH METRIC + //------------------------------------- + if overallSuccess { + ch <- prometheus.MustNewConstMetric(c.redfishUpDesc, prometheus.GaugeValue, 1) + } else { + ch <- prometheus.MustNewConstMetric(c.redfishUpDesc, prometheus.GaugeValue, 0) + } + //------------------------------------- + // 4. SCRAPE DURATION + //------------------------------------- + duration := time.Since(start).Seconds() ch <- prometheus.MustNewConstMetric( - c.redfishUpDesc, + c.scrapeDurationDesc, prometheus.GaugeValue, - 1, + duration, ) } From 9f403db97e43e7fade83eedda3baea70c5cc20f0 Mon Sep 17 00:00:00 2001 From: Jignesh Atul Paratane Date: Thu, 19 Feb 2026 18:05:16 +0530 Subject: [PATCH 7/7] Removed trivial comments from redfish_collector.go file. #5 --- internal/collector/redfish_collector.go | 33 +------------------------ 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/internal/collector/redfish_collector.go b/internal/collector/redfish_collector.go index ae2631a..450f2b2 100644 --- a/internal/collector/redfish_collector.go +++ b/internal/collector/redfish_collector.go @@ -17,15 +17,12 @@ type RedfishAPI interface { type RedfishCollector struct { client RedfishAPI - // Power powerConsumedDesc *prometheus.Desc powerCapacityDesc *prometheus.Desc - // Health redfishUpDesc *prometheus.Desc scrapeDurationDesc *prometheus.Desc - // Temperature metrics readingCelsiusDesc *prometheus.Desc lowerThresholdCriticalDesc *prometheus.Desc lowerThresholdFatalDesc *prometheus.Desc @@ -39,7 +36,6 @@ func NewRedfishCollector(client RedfishAPI) *RedfishCollector { return &RedfishCollector{ client: client, - // Power powerConsumedDesc: prometheus.NewDesc( "redfish_power_consumed_watts", "Current PSU power consumption in watts", @@ -54,7 +50,6 @@ func NewRedfishCollector(client RedfishAPI) *RedfishCollector { nil, ), - // Overall health redfishUpDesc: prometheus.NewDesc( "redfish_up", "Overall Redfish scrape status (1 = success, 0 = failure)", @@ -69,7 +64,6 @@ func NewRedfishCollector(client RedfishAPI) *RedfishCollector { nil, ), - // Temperature metrics readingCelsiusDesc: prometheus.NewDesc( "redfish_temperature_reading_celsius", "Current temperature reading", @@ -122,15 +116,13 @@ func NewRedfishCollector(client RedfishAPI) *RedfishCollector { } func (c *RedfishCollector) Describe(ch chan<- *prometheus.Desc) { - // Power + ch <- c.powerConsumedDesc ch <- c.powerCapacityDesc - // Health ch <- c.redfishUpDesc ch <- c.scrapeDurationDesc - // Temperature ch <- c.readingCelsiusDesc ch <- c.lowerThresholdCriticalDesc ch <- c.lowerThresholdFatalDesc @@ -144,9 +136,6 @@ func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { start := time.Now() overallSuccess := true - //------------------------------------- - // 1. POWER ENDPOINT - //------------------------------------- var power models.PowerControl status, err := c.client.Get(redfish.Power_Endpoints[0], &power) @@ -165,9 +154,6 @@ func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { ) } - //------------------------------------- - // 2. TEMPERATURE ENDPOINTS - //------------------------------------- for _, endpoint := range redfish.Temperature_Endpoints { var t models.Temperature status, err := c.client.Get(endpoint, &t) @@ -184,12 +170,8 @@ func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { continue } - // Labels labels := []string{t.Name, t.PhysicalContext, strconv.Itoa(t.SensorNumber)} - //------------------------------------- - // Emit temperature metrics - //------------------------------------- if t.ReadingCelsius != nil { ch <- prometheus.MustNewConstMetric( c.readingCelsiusDesc, @@ -198,9 +180,7 @@ func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { labels..., ) } - // ---- SAFE THRESHOLD EMITS ---- - // Lower Critical if t.LowerThresholdCritical != nil { ch <- prometheus.MustNewConstMetric( c.lowerThresholdCriticalDesc, @@ -210,7 +190,6 @@ func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { ) } - // Lower Fatal if t.LowerThresholdFatal != nil { ch <- prometheus.MustNewConstMetric( c.lowerThresholdFatalDesc, @@ -220,7 +199,6 @@ func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { ) } - // Upper Critical if t.UpperThresholdCritical != nil { ch <- prometheus.MustNewConstMetric( c.upperThresholdCriticalDesc, @@ -230,7 +208,6 @@ func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { ) } - // Upper Fatal if t.UpperThresholdFatal != nil { ch <- prometheus.MustNewConstMetric( c.upperThresholdFatalDesc, @@ -240,7 +217,6 @@ func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { ) } - // Lower Non-Critical if t.LowerThresholdNonCritical != nil { ch <- prometheus.MustNewConstMetric( c.lowerThresholdNonCriticalDesc, @@ -250,7 +226,6 @@ func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { ) } - // Upper Non-Critical if t.UpperThresholdNonCritical != nil { ch <- prometheus.MustNewConstMetric( c.upperThresholdNonCriticalDesc, @@ -261,18 +236,12 @@ func (c *RedfishCollector) Collect(ch chan<- prometheus.Metric) { } } - //------------------------------------- - // 3. EXPORTER HEALTH METRIC - //------------------------------------- if overallSuccess { ch <- prometheus.MustNewConstMetric(c.redfishUpDesc, prometheus.GaugeValue, 1) } else { ch <- prometheus.MustNewConstMetric(c.redfishUpDesc, prometheus.GaugeValue, 0) } - //------------------------------------- - // 4. SCRAPE DURATION - //------------------------------------- duration := time.Since(start).Seconds() ch <- prometheus.MustNewConstMetric( c.scrapeDurationDesc,