Skip to content

Commit e1e824b

Browse files
committed
Implement proper unregistering
1 parent 5d81b9b commit e1e824b

File tree

6 files changed

+95
-60
lines changed

6 files changed

+95
-60
lines changed

README.md

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,45 @@ Makes available the following metrics for Prometheus for processes matching a gi
1717
### Usage
1818

1919
```sh
20-
./process_exporter -namespace # Prometheus metric namespace
20+
./process_exporter -namespace # Prometheus metric namespace (default: "my")
2121
-binary # Name of binary to monitor
22-
-nameflag # Infer value of "name"-label from value of this command line flag of monitored process
22+
-nameflag # Infer value of "name"-label from value of this command line flag of monitored process (default: "name")
2323
-port # Port to listen on for request (default: 80)
24-
-interval # Interval between metrics being refreshed (default: 10 seconds)
24+
-interval # Interval between metrics being refreshed, in seconds (default: 10)
25+
```
26+
27+
### Metrics
28+
29+
Example output from `curl localhost/metrics` for `process_exporter -binary top -nameflag d` for `top -d 1`. (Exploiting top's `-d` parameter as a unique identifier)
30+
31+
```sh
32+
# HELP my_cpu Process CPU usage (%)
33+
# TYPE my_cpu gauge
34+
my_cpu{bin="top",name="1",pid="26436"} 3.0630784711756576
35+
36+
# HELP my_ram Process RAM usage (bytes)
37+
# TYPE my_ram gauge
38+
my_ram{bin="top",name="1",pid="26436"} 3.80928e+06
39+
40+
# HELP my_storage_read_bytes Total read from storage (bytes)
41+
# TYPE my_storage_read_bytes gauge
42+
my_storage_read_bytes{bin="top",name="1",pid="26436"} 0
43+
44+
# HELP my_storage_reads Total reads from storage
45+
# TYPE my_storage_reads gauge
46+
my_storage_reads{bin="top",name="1",pid="26436"} 27973
47+
48+
# HELP my_storage_write_bytes Total written to storage (bytes)
49+
# TYPE my_storage_write_bytes gauge
50+
my_storage_write_bytes{bin="top",name="1",pid="26436"} 0
51+
52+
# HELP my_storage_writes Total writes to storage
53+
# TYPE my_storage_writes gauge
54+
my_storage_writes{bin="top",name="1",pid="26436"} 91
55+
56+
# HELP my_swap Process swap usage (bytes)
57+
# TYPE my_swap gauge
58+
my_swap{bin="top",name="1",pid="26436"} 0
2559
```
2660

2761
### TODO

cmd/exporter/flags/flags.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import "flag"
44

55
func Parse(arguments []string) (namespace, binary, argName string, port int, interval float64) {
66
flagSet := flag.NewFlagSet("flags", flag.ExitOnError)
7-
namespacePtr := flagSet.String("namespace", "mine", "Prometheus metric namespace.")
7+
namespacePtr := flagSet.String("namespace", "my", "Prometheus metric namespace.")
88
binaryPtr := flagSet.String("binary", "", "Filter which processes to watch by binary name. This is limited to 15 bytes because of the kernel.")
99
nameFlagPtr := flagSet.String("nameflag", "name", "Set Prometheus \"name\"-label value to value of this command line argument of the monitored processes.")
1010
portPtr := flagSet.Int("port", 80, "Port on which to listen to requests to /metrics.")

cmd/exporter/metrics/proc_metrics.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ import (
88
)
99

1010
type ProcessMetrics struct {
11-
cpuDuration float64
12-
cpuSampleTime time.Time
13-
ram uint64
14-
swap uint64
15-
diskReadBytes uint64
16-
diskWriteBytes uint64
17-
diskReadCount uint64
18-
diskWriteCount uint64
11+
cpuDuration float64
12+
cpuSampleTime time.Time
13+
ram uint64
14+
swap uint64
15+
storageReadBytes uint64
16+
storageWriteBytes uint64
17+
storageReadCount uint64
18+
storageWriteCount uint64
1919
}
2020

2121
func getProcMetrics(pid int) (processMetrics *ProcessMetrics, err error) {
@@ -39,9 +39,9 @@ func getProcMetrics(pid int) (processMetrics *ProcessMetrics, err error) {
3939
if err != nil {
4040
return nil, fmt.Errorf("could not read disk IO info of PID %d: %w", pid, err)
4141
}
42-
m.diskReadBytes = ioDisk.ReadBytes
43-
m.diskWriteBytes = ioDisk.WriteBytes
44-
m.diskReadCount = ioDisk.ReadCount
45-
m.diskWriteCount = ioDisk.WriteCount
42+
m.storageReadBytes = ioDisk.ReadBytes
43+
m.storageWriteBytes = ioDisk.WriteBytes
44+
m.storageReadCount = ioDisk.ReadCount
45+
m.storageWriteCount = ioDisk.WriteCount
4646
return m, nil
4747
}

cmd/exporter/metrics/prom_proc_metrics.go

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,23 @@ import (
1010
)
1111

1212
type PrometheusProcessMetrics struct {
13-
previousMetrics *ProcessMetrics
14-
cpuGauge prometheus.Gauge
15-
ramGauge prometheus.Gauge
16-
swapGauge prometheus.Gauge
17-
diskReadBytesGauge prometheus.Gauge
18-
diskWriteBytesGauge prometheus.Gauge
19-
diskReadCountGauge prometheus.Gauge
20-
diskWriteCountGauge prometheus.Gauge
13+
registeredCollectors []prometheus.Collector
14+
previousMetrics *ProcessMetrics
15+
cpuGauge prometheus.Gauge
16+
ramGauge prometheus.Gauge
17+
swapGauge prometheus.Gauge
18+
storageReadBytesGauge prometheus.Gauge
19+
storageWriteBytesGauge prometheus.Gauge
20+
storagediskReadCountGauge prometheus.Gauge
21+
storageWriteCountGauge prometheus.Gauge
2122
}
2223

2324
func newPrometheusProcessMetrics(proc ps.Process, descriptiveName, metricNamespace string) (processMetrics *PrometheusProcessMetrics) {
2425
processMetrics = &PrometheusProcessMetrics{}
2526
binaryName := filepath.Base(proc.Executable())
2627
pid := fmt.Sprintf("%d", proc.Pid())
2728
processMetrics.makeGauges(metricNamespace, pid, binaryName, descriptiveName)
28-
processMetrics.makeDiskGauges(metricNamespace, pid, binaryName, descriptiveName)
29+
processMetrics.makeStorageGauges(metricNamespace, pid, binaryName, descriptiveName)
2930
return processMetrics
3031
}
3132

@@ -50,81 +51,78 @@ func (pm *PrometheusProcessMetrics) makeGauges(metricNamespace, pid, binaryName,
5051
})
5152
}
5253

53-
func (pm *PrometheusProcessMetrics) makeDiskGauges(metricNamespace, pid, binaryName, descriptiveName string) {
54-
pm.diskReadBytesGauge = prometheus.NewGauge(prometheus.GaugeOpts{
54+
func (pm *PrometheusProcessMetrics) makeStorageGauges(metricNamespace, pid, binaryName, descriptiveName string) {
55+
pm.storageReadBytesGauge = prometheus.NewGauge(prometheus.GaugeOpts{
5556
Namespace: metricNamespace,
56-
Name: "disk_read_bytes",
57-
Help: "Total read from disk (bytes)",
57+
Name: "storage_read_bytes",
58+
Help: "Total read from storage (bytes)",
5859
ConstLabels: prometheus.Labels{"pid": pid, "bin": binaryName, "name": descriptiveName},
5960
})
60-
pm.diskWriteBytesGauge = prometheus.NewGauge(prometheus.GaugeOpts{
61+
pm.storageWriteBytesGauge = prometheus.NewGauge(prometheus.GaugeOpts{
6162
Namespace: metricNamespace,
62-
Name: "disk_write_bytes",
63-
Help: "Total written to disk (bytes)",
63+
Name: "storage_write_bytes",
64+
Help: "Total written to storage (bytes)",
6465
ConstLabels: prometheus.Labels{"pid": pid, "bin": binaryName, "name": descriptiveName},
6566
})
66-
pm.diskReadCountGauge = prometheus.NewGauge(prometheus.GaugeOpts{
67+
pm.storagediskReadCountGauge = prometheus.NewGauge(prometheus.GaugeOpts{
6768
Namespace: metricNamespace,
68-
Name: "disk_reads",
69-
Help: "Total reads from disk",
69+
Name: "storage_reads",
70+
Help: "Total reads from storage",
7071
ConstLabels: prometheus.Labels{"pid": pid, "bin": binaryName, "name": descriptiveName},
7172
})
72-
pm.diskWriteCountGauge = prometheus.NewGauge(prometheus.GaugeOpts{
73+
pm.storageWriteCountGauge = prometheus.NewGauge(prometheus.GaugeOpts{
7374
Namespace: metricNamespace,
74-
Name: "disk_writes",
75-
Help: "Total writes to disk",
75+
Name: "storage_writes",
76+
Help: "Total writes to storage",
7677
ConstLabels: prometheus.Labels{"pid": pid, "bin": binaryName, "name": descriptiveName},
7778
})
7879
}
7980

8081
func (pm *PrometheusProcessMetrics) Register() error {
81-
registeredCollectors := make([]prometheus.Collector, 0)
82+
pm.Unregister()
8283
var err error
8384
for _, collector := range []prometheus.Collector{
8485
pm.cpuGauge,
8586
pm.ramGauge,
8687
pm.swapGauge,
87-
pm.diskReadBytesGauge,
88-
pm.diskWriteBytesGauge,
89-
pm.diskReadCountGauge,
90-
pm.diskWriteCountGauge,
88+
pm.storageReadBytesGauge,
89+
pm.storageWriteBytesGauge,
90+
pm.storagediskReadCountGauge,
91+
pm.storageWriteCountGauge,
9192
} {
9293
err = prometheus.Register(collector)
9394
if err != nil {
9495
break
9596
}
96-
registeredCollectors = append(registeredCollectors, collector)
97+
pm.registeredCollectors = append(pm.registeredCollectors, collector)
9798
}
9899
if err != nil {
99-
for _, collector := range registeredCollectors {
100-
prometheus.Unregister(collector)
101-
}
100+
pm.Unregister()
102101
}
103102
return err
104103
}
105104

106105
func (pm *PrometheusProcessMetrics) Unregister() {
107-
prometheus.Unregister(pm.cpuGauge)
108-
}
109-
110-
func (pm *PrometheusProcessMetrics) Update() {
111-
prometheus.Unregister(pm.cpuGauge)
106+
for _, collector := range pm.registeredCollectors {
107+
prometheus.Unregister(collector)
108+
}
109+
pm.registeredCollectors = nil
112110
}
113111

114112
func (pm *PrometheusProcessMetrics) Set(processMetrics *ProcessMetrics) {
115113
if pm.previousMetrics != nil {
116114
deltaTime := processMetrics.cpuSampleTime.Sub(pm.previousMetrics.cpuSampleTime).Seconds()
117115
if deltaTime > 0 {
118-
pm.cpuGauge.Set((processMetrics.cpuDuration - pm.previousMetrics.cpuDuration) / deltaTime)
116+
pm.cpuGauge.Set(((processMetrics.cpuDuration - pm.previousMetrics.cpuDuration) * 100) / deltaTime)
119117
} else {
120118
log.Warn("deltaTime <= 0")
121119
}
122120
}
123121
pm.ramGauge.Set(float64(processMetrics.ram))
124122
pm.swapGauge.Set(float64(processMetrics.swap))
125-
pm.diskReadBytesGauge.Set(float64(processMetrics.diskReadBytes))
126-
pm.diskWriteBytesGauge.Set(float64(processMetrics.diskWriteBytes))
127-
pm.diskReadCountGauge.Set(float64(processMetrics.diskReadCount))
128-
pm.diskWriteCountGauge.Set(float64(processMetrics.diskWriteCount))
123+
pm.storageReadBytesGauge.Set(float64(processMetrics.storageReadBytes))
124+
pm.storageWriteBytesGauge.Set(float64(processMetrics.storageWriteBytes))
125+
pm.storagediskReadCountGauge.Set(float64(processMetrics.storageReadCount))
126+
pm.storageWriteCountGauge.Set(float64(processMetrics.storageWriteCount))
129127
pm.previousMetrics = processMetrics
130128
}

cmd/exporter/metrics/prom_proc_metrics_set.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func (set *PrometheusProcessMetricsSet) UpdateMetrics() {
108108
func updateMetrics(pm *PrometheusProcessMetrics, withPid int) {
109109
processMetrics, err := getProcMetrics(withPid)
110110
if err != nil {
111-
log.Warn(fmt.Sprintf("Could not determine metrics for process %d: %v.", withPid, err))
111+
log.Warn(fmt.Sprintf("Could not determy metrics for process %d: %v.", withPid, err))
112112
return
113113
}
114114
pm.Set(processMetrics)
@@ -127,7 +127,10 @@ func procDescriptiveName(pid int, nameFlag string) (string, error) {
127127
}
128128

129129
func descriptiveNameFromArgs(args []string, flagName string) (string, error) {
130-
if len(args) <= 1 {
130+
if len(args) == 0 {
131+
return "", fmt.Errorf("no arguments")
132+
}
133+
if len(args) == 1 {
131134
return "", fmt.Errorf("too few arguments")
132135
}
133136
args = args[1:]

integration_test/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func main() {
6969
lines := strings.Split(contentsString, "\n")
7070
gotLine := false
7171
for _, line := range lines {
72-
prefix := fmt.Sprintf("mine_disk_write_bytes{bin=\"%s\",name=\"%s\",pid=\"%d\"} ", dummyBinaryName, dummyDescripiveName, cmdDummy.Process.Pid)
72+
prefix := fmt.Sprintf("my_storage_write_bytes{bin=\"%s\",name=\"%s\",pid=\"%d\"} ", dummyBinaryName, dummyDescripiveName, cmdDummy.Process.Pid)
7373
if strings.HasPrefix(line, prefix) {
7474
writeBytes, err := strconv.Atoi(line[len(prefix):])
7575
if err != nil {

0 commit comments

Comments
 (0)