Skip to content

Commit 8afccc7

Browse files
feat: Add new CollectorFunc utility (#1724)
* feat: add CollectorFunc utility Signed-off-by: Saumyacodes-40 <[email protected]> * update Signed-off-by: Saumyacodes-40 <[email protected]> * added license to the test Signed-off-by: Saumyacodes-40 <[email protected]> * address req changes Signed-off-by: Saumyacodes-40 <[email protected]> * update license part in test file Signed-off-by: Saumyacodes-40 <[email protected]> * add collectorFunc example to prometheus/examples_test.go Signed-off-by: Saumyacodes-40 <[email protected]> --------- Signed-off-by: Saumyacodes-40 <[email protected]>
1 parent a42ae02 commit 8afccc7

File tree

3 files changed

+161
-0
lines changed

3 files changed

+161
-0
lines changed

prometheus/collectorfunc.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2025 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package prometheus
15+
16+
// CollectorFunc is a convenient way to implement a Prometheus Collector
17+
// without interface boilerplate.
18+
// This implementation is based on DescribeByCollect method.
19+
// familiarize yourself to it before using.
20+
type CollectorFunc func(chan<- Metric)
21+
22+
// Collect calls the defined CollectorFunc function with the provided Metrics channel
23+
func (f CollectorFunc) Collect(ch chan<- Metric) {
24+
f(ch)
25+
}
26+
27+
// Describe sends the descriptor information using DescribeByCollect
28+
func (f CollectorFunc) Describe(ch chan<- *Desc) {
29+
DescribeByCollect(f, ch)
30+
}

prometheus/collectorfunc_test.go

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright 2025 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package prometheus
15+
16+
import "testing"
17+
18+
func TestCollectorFunc(t *testing.T) {
19+
testDesc := NewDesc(
20+
"test_metric",
21+
"A test metric",
22+
nil, nil,
23+
)
24+
25+
cf := CollectorFunc(func(ch chan<- Metric) {
26+
ch <- MustNewConstMetric(
27+
testDesc,
28+
GaugeValue,
29+
42.0,
30+
)
31+
})
32+
33+
ch := make(chan Metric, 1)
34+
cf.Collect(ch)
35+
close(ch)
36+
37+
metric := <-ch
38+
if metric == nil {
39+
t.Fatal("Expected metric, got nil")
40+
}
41+
42+
descCh := make(chan *Desc, 1)
43+
cf.Describe(descCh)
44+
close(descCh)
45+
46+
desc := <-descCh
47+
if desc == nil {
48+
t.Fatal("Expected desc, got nil")
49+
}
50+
51+
if desc.String() != testDesc.String() {
52+
t.Fatalf("Expected %s, got %s", testDesc.String(), desc.String())
53+
}
54+
}
55+
56+
func TestCollectorFuncWithRegistry(t *testing.T) {
57+
reg := NewPedanticRegistry()
58+
59+
cf := CollectorFunc(func(ch chan<- Metric) {
60+
ch <- MustNewConstMetric(
61+
NewDesc(
62+
"test_metric",
63+
"A test metric",
64+
nil, nil,
65+
),
66+
GaugeValue,
67+
42.0,
68+
)
69+
})
70+
71+
if err := reg.Register(cf); err != nil {
72+
t.Errorf("Failed to register CollectorFunc: %v", err)
73+
}
74+
75+
collectedMetrics, err := reg.Gather()
76+
if err != nil {
77+
t.Errorf("Failed to gather metrics: %v", err)
78+
}
79+
80+
if len(collectedMetrics) != 1 {
81+
t.Errorf("Expected 1 metric family, got %d", len(collectedMetrics))
82+
}
83+
}

prometheus/examples_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -736,3 +736,51 @@ func ExampleNewConstMetricWithCreatedTimestamp() {
736736
// Output:
737737
// {"counter":{"value":1257894000,"createdTimestamp":"1970-01-01T00:00:00Z"}}
738738
}
739+
740+
// Using CollectorFunc that registers the metric info for the HTTP requests.
741+
func ExampleCollectorFunc() {
742+
desc := prometheus.NewDesc(
743+
"http_requests_info",
744+
"Information about the received HTTP requests.",
745+
[]string{"code", "method"},
746+
nil,
747+
)
748+
749+
// Example 1: 42 GET requests with 200 OK status code.
750+
collector := prometheus.CollectorFunc(func(ch chan<- prometheus.Metric) {
751+
ch <- prometheus.MustNewConstMetric(
752+
desc,
753+
prometheus.CounterValue, // Metric type: Counter
754+
42, // Value
755+
"200", // Label value: HTTP status code
756+
"GET", // Label value: HTTP method
757+
)
758+
759+
// Example 2: 15 POST requests with 404 Not Found status code.
760+
ch <- prometheus.MustNewConstMetric(
761+
desc,
762+
prometheus.CounterValue,
763+
15,
764+
"404",
765+
"POST",
766+
)
767+
})
768+
769+
prometheus.MustRegister(collector)
770+
771+
// Just for demonstration, let's check the state of the metric by registering
772+
// it with a custom registry and then let it collect the metrics.
773+
774+
reg := prometheus.NewRegistry()
775+
reg.MustRegister(collector)
776+
777+
metricFamilies, err := reg.Gather()
778+
if err != nil || len(metricFamilies) != 1 {
779+
panic("unexpected behavior of custom test registry")
780+
}
781+
782+
fmt.Println(toNormalizedJSON(sanitizeMetricFamily(metricFamilies[0])))
783+
784+
// Output:
785+
// {"name":"http_requests_info","help":"Information about the received HTTP requests.","type":"COUNTER","metric":[{"label":[{"name":"code","value":"200"},{"name":"method","value":"GET"}],"counter":{"value":42}},{"label":[{"name":"code","value":"404"},{"name":"method","value":"POST"}],"counter":{"value":15}}]}
786+
}

0 commit comments

Comments
 (0)