Skip to content

Commit 1a1b860

Browse files
committed
process_collector: Add Platform-Specific Describe for processCollector
Signed-off-by: Ying WANG <[email protected]>
1 parent ac114f3 commit 1a1b860

8 files changed

+186
-26
lines changed

prometheus/process_collector.go

+17-14
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
type processCollector struct {
2525
collectFn func(chan<- Metric)
26+
describeFn func(chan<- *Desc)
2627
pidFn func() (int, error)
2728
reportErrors bool
2829
cpuTotal *Desc
@@ -122,33 +123,35 @@ func NewProcessCollector(opts ProcessCollectorOpts) Collector {
122123
// Set up process metric collection if supported by the runtime.
123124
if canCollectProcess() {
124125
c.collectFn = c.processCollect
126+
c.describeFn = c.describe
125127
} else {
126-
c.collectFn = func(ch chan<- Metric) {
127-
c.reportError(ch, nil, errors.New("process metrics not supported on this platform"))
128-
}
128+
c.collectFn = c.defaultCollectFn
129+
c.describeFn = c.defaultDescribeFn
129130
}
130131

131132
return c
132133
}
133134

134-
// Describe returns all descriptions of the collector.
135-
func (c *processCollector) Describe(ch chan<- *Desc) {
136-
ch <- c.cpuTotal
137-
ch <- c.openFDs
138-
ch <- c.maxFDs
139-
ch <- c.vsize
140-
ch <- c.maxVsize
141-
ch <- c.rss
142-
ch <- c.startTime
143-
ch <- c.inBytes
144-
ch <- c.outBytes
135+
func (c *processCollector) defaultCollectFn(ch chan<- Metric) {
136+
c.reportError(ch, nil, errors.New("process metrics not supported on this platform"))
137+
}
138+
139+
func (c *processCollector) defaultDescribeFn(ch chan<- *Desc) {
140+
if c.reportErrors {
141+
ch <- NewInvalidDesc(errors.New("process metrics not supported on this platform"))
142+
}
145143
}
146144

147145
// Collect returns the current state of all metrics of the collector.
148146
func (c *processCollector) Collect(ch chan<- Metric) {
149147
c.collectFn(ch)
150148
}
151149

150+
// Describe returns all descriptions of the collector.
151+
func (c *processCollector) Describe(ch chan<- *Desc) {
152+
c.describeFn(ch)
153+
}
154+
152155
func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error) {
153156
if !c.reportErrors {
154157
return

prometheus/process_collector_darwin.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ package prometheus
1515

1616
import (
1717
"fmt"
18-
"golang.org/x/sys/unix"
1918
"os"
2019
"syscall"
2120
"time"
21+
22+
"golang.org/x/sys/unix"
2223
)
2324

2425
func canCollectProcess() bool {
@@ -58,6 +59,25 @@ func getOpenFileCount() (float64, error) {
5859
}
5960
}
6061

62+
// describe returns all descriptions of the collector for Darwin.
63+
// Ensure that this list of descriptors is kept in sync with the metrics collected
64+
// in the processCollect method. Any changes to the metrics in processCollect
65+
// (such as adding or removing metrics) should be reflected in this list of descriptors.
66+
func (c *processCollector) describe(ch chan<- *Desc) {
67+
ch <- c.cpuTotal
68+
ch <- c.openFDs
69+
ch <- c.maxFDs
70+
ch <- c.maxVsize
71+
ch <- c.startTime
72+
73+
/* the process could be collected but not implemented yet
74+
ch <- c.rss
75+
ch <- c.vsize
76+
ch <- c.inBytes
77+
ch <- c.outBytes
78+
*/
79+
}
80+
6181
func (c *processCollector) processCollect(ch chan<- Metric) {
6282
if procs, err := unix.SysctlKinfoProcSlice("kern.proc.pid", os.Getpid()); err == nil {
6383
if len(procs) == 1 {

prometheus/process_collector_js.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,14 @@ func canCollectProcess() bool {
2020
return false
2121
}
2222

23+
// describe returns all descriptions of the collector for js.
24+
// Ensure that this list of descriptors is kept in sync with the metrics collected
25+
// in the processCollect method. Any changes to the metrics in processCollect
26+
// (such as adding or removing metrics) should be reflected in this list of descriptors.
2327
func (c *processCollector) processCollect(ch chan<- Metric) {
24-
// noop on this platform
25-
return
28+
c.defaultCollect(ch)
29+
}
30+
31+
func (c *processCollector) describe(ch chan<- *Desc) {
32+
c.defaultDescribe(ch)
2633
}

prometheus/process_collector_other.go

+16
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,19 @@ func (c *processCollector) processCollect(ch chan<- Metric) {
7878
c.reportError(ch, nil, err)
7979
}
8080
}
81+
82+
// describe returns all descriptions of the collector for others than windows, js, wasip1 and darwin.
83+
// Ensure that this list of descriptors is kept in sync with the metrics collected
84+
// in the processCollect method. Any changes to the metrics in processCollect
85+
// (such as adding or removing metrics) should be reflected in this list of descriptors.
86+
func (c *processCollector) describe(ch chan<- *Desc) {
87+
ch <- c.cpuTotal
88+
ch <- c.openFDs
89+
ch <- c.maxFDs
90+
ch <- c.vsize
91+
ch <- c.maxVsize
92+
ch <- c.rss
93+
ch <- c.startTime
94+
ch <- c.inBytes
95+
ch <- c.outBytes
96+
}

prometheus/process_collector_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,52 @@ func TestNewPidFileFn(t *testing.T) {
170170
}
171171
}
172172
}
173+
174+
func TestDescribeAndCollectAlignment(t *testing.T) {
175+
collector := &processCollector{
176+
pidFn: getPIDFn(),
177+
cpuTotal: NewDesc("cpu_total", "Total CPU usage", nil, nil),
178+
openFDs: NewDesc("open_fds", "Number of open file descriptors", nil, nil),
179+
maxFDs: NewDesc("max_fds", "Maximum file descriptors", nil, nil),
180+
vsize: NewDesc("vsize", "Virtual memory size", nil, nil),
181+
maxVsize: NewDesc("max_vsize", "Maximum virtual memory size", nil, nil),
182+
rss: NewDesc("rss", "Resident Set Size", nil, nil),
183+
startTime: NewDesc("start_time", "Process start time", nil, nil),
184+
inBytes: NewDesc("in_bytes", "Input bytes", nil, nil),
185+
outBytes: NewDesc("out_bytes", "Output bytes", nil, nil),
186+
}
187+
188+
// Collect and get descriptors
189+
descCh := make(chan *Desc, 15)
190+
collector.describe(descCh)
191+
close(descCh)
192+
193+
definedDescs := make(map[string]bool)
194+
for desc := range descCh {
195+
definedDescs[desc.String()] = true
196+
}
197+
198+
// Collect and get metrics
199+
metricsCh := make(chan Metric, 15)
200+
collector.processCollect(metricsCh)
201+
close(metricsCh)
202+
203+
collectedMetrics := make(map[string]bool)
204+
for metric := range metricsCh {
205+
collectedMetrics[metric.Desc().String()] = true
206+
}
207+
208+
// Verify that all described metrics are collected
209+
for desc := range definedDescs {
210+
if !collectedMetrics[desc] {
211+
t.Errorf("Metric %s described but not collected", desc)
212+
}
213+
}
214+
215+
// Verify that no extra metrics are collected
216+
for desc := range collectedMetrics {
217+
if !definedDescs[desc] {
218+
t.Errorf("Metric %s collected but not described", desc)
219+
}
220+
}
221+
}

prometheus/process_collector_wasip1.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,14 @@ func canCollectProcess() bool {
2020
return false
2121
}
2222

23-
func (*processCollector) processCollect(chan<- Metric) {
24-
// noop on this platform
25-
return
23+
func (c *processCollector) processCollect(ch chan<- Metric) {
24+
c.defaultCollect(ch)
25+
}
26+
27+
// describe returns all descriptions of the collector for wasip1.
28+
// Ensure that this list of descriptors is kept in sync with the metrics collected
29+
// in the processCollect method. Any changes to the metrics in processCollect
30+
// (such as adding or removing metrics) should be reflected in this list of descriptors.
31+
func (c *processCollector) describe(ch chan<- *Desc) {
32+
c.defaultDescribe(ch)
2633
}

prometheus/process_collector_windows.go

+15-6
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,10 @@ func getProcessHandleCount(handle windows.Handle) (uint32, error) {
7979
}
8080

8181
func (c *processCollector) processCollect(ch chan<- Metric) {
82-
h, err := windows.GetCurrentProcess()
83-
if err != nil {
84-
c.reportError(ch, nil, err)
85-
return
86-
}
82+
h := windows.CurrentProcess()
8783

8884
var startTime, exitTime, kernelTime, userTime windows.Filetime
89-
err = windows.GetProcessTimes(h, &startTime, &exitTime, &kernelTime, &userTime)
85+
err := windows.GetProcessTimes(h, &startTime, &exitTime, &kernelTime, &userTime)
9086
if err != nil {
9187
c.reportError(ch, nil, err)
9288
return
@@ -111,6 +107,19 @@ func (c *processCollector) processCollect(ch chan<- Metric) {
111107
ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(16*1024*1024)) // Windows has a hard-coded max limit, not per-process.
112108
}
113109

110+
// describe returns all descriptions of the collector for windows.
111+
// Ensure that this list of descriptors is kept in sync with the metrics collected
112+
// in the processCollect method. Any changes to the metrics in processCollect
113+
// (such as adding or removing metrics) should be reflected in this list of descriptors.
114+
func (c *processCollector) describe(ch chan<- *Desc) {
115+
ch <- c.cpuTotal
116+
ch <- c.openFDs
117+
ch <- c.maxFDs
118+
ch <- c.vsize
119+
ch <- c.rss
120+
ch <- c.startTime
121+
}
122+
114123
func fileTimeToSeconds(ft windows.Filetime) float64 {
115124
return float64(uint64(ft.HighDateTime)<<32+uint64(ft.LowDateTime)) / 1e7
116125
}

prometheus/process_collector_windows_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,52 @@ func TestWindowsProcessCollector(t *testing.T) {
6868
}
6969
}
7070
}
71+
72+
func TestWindowsDescribeAndCollectAlignment(t *testing.T) {
73+
collector := &processCollector{
74+
pidFn: getPIDFn(),
75+
cpuTotal: NewDesc("cpu_total", "Total CPU usage", nil, nil),
76+
openFDs: NewDesc("open_fds", "Number of open file descriptors", nil, nil),
77+
maxFDs: NewDesc("max_fds", "Maximum file descriptors", nil, nil),
78+
vsize: NewDesc("vsize", "Virtual memory size", nil, nil),
79+
maxVsize: NewDesc("max_vsize", "Maximum virtual memory size", nil, nil),
80+
rss: NewDesc("rss", "Resident Set Size", nil, nil),
81+
startTime: NewDesc("start_time", "Process start time", nil, nil),
82+
inBytes: NewDesc("in_bytes", "Input bytes", nil, nil),
83+
outBytes: NewDesc("out_bytes", "Output bytes", nil, nil),
84+
}
85+
86+
// Collect and get descriptors
87+
descCh := make(chan *Desc, 15)
88+
collector.describe(descCh)
89+
close(descCh)
90+
91+
definedDescs := make(map[string]bool)
92+
for desc := range descCh {
93+
definedDescs[desc.String()] = true
94+
}
95+
96+
// Collect and get metrics
97+
metricsCh := make(chan Metric, 15)
98+
collector.processCollect(metricsCh)
99+
close(metricsCh)
100+
101+
collectedMetrics := make(map[string]bool)
102+
for metric := range metricsCh {
103+
collectedMetrics[metric.Desc().String()] = true
104+
}
105+
106+
// Verify that all described metrics are collected
107+
for desc := range definedDescs {
108+
if !collectedMetrics[desc] {
109+
t.Errorf("Metric %s described but not collected", desc)
110+
}
111+
}
112+
113+
// Verify that no extra metrics are collected
114+
for desc := range collectedMetrics {
115+
if !definedDescs[desc] {
116+
t.Errorf("Metric %s collected but not described", desc)
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)