Skip to content

Commit 705567c

Browse files
committed
Add client and system info metrics
1 parent fb60a03 commit 705567c

19 files changed

+5468
-92
lines changed

collectors/clients_collector.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package collectors
2+
3+
import (
4+
"github.com/DRuggeri/netgear_client"
5+
"github.com/prometheus/client_golang/prometheus"
6+
"github.com/prometheus/common/log"
7+
"strconv"
8+
"time"
9+
)
10+
11+
type ClientCollector struct {
12+
namespace string
13+
client *netgear_client.NetgearClient
14+
clientsMetric *prometheus.GaugeVec
15+
wirelessSpeedMetric *prometheus.GaugeVec
16+
wirelessStrengthMetric *prometheus.GaugeVec
17+
18+
scrapesTotalMetric prometheus.Counter
19+
scrapeErrorsTotalMetric prometheus.Counter
20+
lastScrapeErrorMetric prometheus.Gauge
21+
lastScrapeTimestampMetric prometheus.Gauge
22+
lastScrapeDurationSecondsMetric prometheus.Gauge
23+
}
24+
25+
func NewClientCollector(namespace string, client *netgear_client.NetgearClient) *ClientCollector {
26+
clientsMetric := prometheus.NewGaugeVec(
27+
prometheus.GaugeOpts{
28+
Namespace: namespace,
29+
Subsystem: "client",
30+
Name: "info",
31+
Help: "Client information with ip, name, MAC address and connection type labels",
32+
},
33+
[]string{"ip", "name", "mac", "connection_type"},
34+
)
35+
36+
wirelessSpeedMetric := prometheus.NewGaugeVec(
37+
prometheus.GaugeOpts{
38+
Namespace: namespace,
39+
Subsystem: "client",
40+
Name: "wireless_speed",
41+
Help: "Wireless speed of clients connected to the network",
42+
},
43+
[]string{"mac"},
44+
)
45+
46+
wirelessStrengthMetric := prometheus.NewGaugeVec(
47+
prometheus.GaugeOpts{
48+
Namespace: namespace,
49+
Subsystem: "client",
50+
Name: "wireless_strength",
51+
Help: "Wireless strength of clients connected to the network",
52+
},
53+
[]string{"mac"},
54+
)
55+
56+
scrapesTotalMetric := prometheus.NewCounter(
57+
prometheus.CounterOpts{
58+
Namespace: namespace,
59+
Subsystem: "client_scrapes",
60+
Name: "total",
61+
Help: "Total number of scrapes for Netgear client stats.",
62+
},
63+
)
64+
65+
scrapeErrorsTotalMetric := prometheus.NewCounter(
66+
prometheus.CounterOpts{
67+
Namespace: namespace,
68+
Subsystem: "client_scrape_errors",
69+
Name: "total",
70+
Help: "Total number of scrapes errors for Netgear client stats.",
71+
},
72+
)
73+
74+
lastScrapeErrorMetric := prometheus.NewGauge(
75+
prometheus.GaugeOpts{
76+
Namespace: namespace,
77+
Subsystem: "",
78+
Name: "last_client_scrape_error",
79+
Help: "Whether the last scrape of Netgear client stats resulted in an error (1 for error, 0 for success).",
80+
},
81+
)
82+
83+
lastScrapeTimestampMetric := prometheus.NewGauge(
84+
prometheus.GaugeOpts{
85+
Namespace: namespace,
86+
Subsystem: "",
87+
Name: "last_client_scrape_timestamp",
88+
Help: "Number of seconds since 1970 since last scrape of Netgear client metrics.",
89+
},
90+
)
91+
92+
lastScrapeDurationSecondsMetric := prometheus.NewGauge(
93+
prometheus.GaugeOpts{
94+
Namespace: namespace,
95+
Subsystem: "",
96+
Name: "last_client_scrape_duration_seconds",
97+
Help: "Duration of the last scrape of Netgear client stats.",
98+
},
99+
)
100+
101+
return &ClientCollector{
102+
namespace: namespace,
103+
client: client,
104+
clientsMetric: clientsMetric,
105+
wirelessSpeedMetric: wirelessSpeedMetric,
106+
wirelessStrengthMetric: wirelessStrengthMetric,
107+
108+
scrapesTotalMetric: scrapesTotalMetric,
109+
scrapeErrorsTotalMetric: scrapeErrorsTotalMetric,
110+
lastScrapeErrorMetric: lastScrapeErrorMetric,
111+
lastScrapeTimestampMetric: lastScrapeTimestampMetric,
112+
lastScrapeDurationSecondsMetric: lastScrapeDurationSecondsMetric,
113+
}
114+
}
115+
116+
func (c *ClientCollector) Collect(ch chan<- prometheus.Metric) {
117+
var begun = time.Now()
118+
119+
errorMetric := float64(0)
120+
clients, err := c.client.GetAttachDevice()
121+
if err != nil {
122+
log.Errorf("Error while collecting client statistics: %v", err)
123+
errorMetric = float64(1)
124+
c.scrapeErrorsTotalMetric.Inc()
125+
} else {
126+
for _, client := range clients {
127+
c.clientsMetric.WithLabelValues(
128+
client["IPAddress"],
129+
client["Name"],
130+
client["MACAddress"],
131+
client["ConnectionType"],
132+
).Set(float64(1))
133+
134+
if client["ConnectionType"] != "wired" {
135+
tmp, _ := strconv.ParseFloat(client["WirelessLinkSpeed"], 64)
136+
c.wirelessSpeedMetric.WithLabelValues(client["MACAddress"]).Set(tmp)
137+
138+
tmp, _ = strconv.ParseFloat(client["WirelessSignalStrength"], 64)
139+
c.wirelessStrengthMetric.WithLabelValues(client["MACAddress"]).Set(tmp)
140+
}
141+
}
142+
}
143+
c.clientsMetric.Collect(ch)
144+
c.wirelessSpeedMetric.Collect(ch)
145+
c.wirelessStrengthMetric.Collect(ch)
146+
147+
c.scrapeErrorsTotalMetric.Collect(ch)
148+
149+
c.scrapesTotalMetric.Inc()
150+
c.scrapesTotalMetric.Collect(ch)
151+
152+
c.lastScrapeErrorMetric.Set(errorMetric)
153+
c.lastScrapeErrorMetric.Collect(ch)
154+
155+
c.lastScrapeTimestampMetric.Set(float64(time.Now().Unix()))
156+
c.lastScrapeTimestampMetric.Collect(ch)
157+
158+
c.lastScrapeDurationSecondsMetric.Set(time.Since(begun).Seconds())
159+
c.lastScrapeDurationSecondsMetric.Collect(ch)
160+
}
161+
162+
func (c *ClientCollector) Describe(ch chan<- *prometheus.Desc) {
163+
c.clientsMetric.Describe(ch)
164+
c.wirelessSpeedMetric.Describe(ch)
165+
c.wirelessStrengthMetric.Describe(ch)
166+
c.scrapesTotalMetric.Describe(ch)
167+
c.scrapeErrorsTotalMetric.Describe(ch)
168+
c.lastScrapeErrorMetric.Describe(ch)
169+
c.lastScrapeTimestampMetric.Describe(ch)
170+
c.lastScrapeDurationSecondsMetric.Describe(ch)
171+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package collectors
2+
3+
import (
4+
"fmt"
5+
"github.com/DRuggeri/netgear_client"
6+
"github.com/prometheus/client_golang/prometheus"
7+
"github.com/prometheus/common/log"
8+
"strconv"
9+
"strings"
10+
"time"
11+
)
12+
13+
type SystemInfo struct {
14+
namespace string
15+
client *netgear_client.NetgearClient
16+
metrics map[string]prometheus.Gauge
17+
18+
scrapesTotalMetric prometheus.Counter
19+
scrapeErrorsTotalMetric prometheus.Counter
20+
lastScrapeErrorMetric prometheus.Gauge
21+
lastScrapeTimestampMetric prometheus.Gauge
22+
lastScrapeDurationSecondsMetric prometheus.Gauge
23+
}
24+
25+
var SystemInfoFields = [...]string{
26+
"CPUUtilization",
27+
"PhysicalMemory",
28+
"MemoryUtilization",
29+
"PhysicalFlash",
30+
"AvailableFlash",
31+
}
32+
33+
func NewSystemInfoCollector(namespace string, client *netgear_client.NetgearClient) *SystemInfo {
34+
metrics := make(map[string]prometheus.Gauge)
35+
for _, name := range SystemInfoFields {
36+
metrics[name] = prometheus.NewGauge(
37+
prometheus.GaugeOpts{
38+
Namespace: namespace,
39+
Subsystem: "system_info",
40+
Name: strings.ToLower(name),
41+
Help: fmt.Sprintf("Value of the '%s' system info metric from the router", name),
42+
},
43+
)
44+
}
45+
46+
scrapesTotalMetric := prometheus.NewCounter(
47+
prometheus.CounterOpts{
48+
Namespace: namespace,
49+
Subsystem: "system_info_scrapes",
50+
Name: "total",
51+
Help: "Total number of scrapes for Netgear system info stats.",
52+
},
53+
)
54+
55+
scrapeErrorsTotalMetric := prometheus.NewCounter(
56+
prometheus.CounterOpts{
57+
Namespace: namespace,
58+
Subsystem: "system_info_scrape_errors",
59+
Name: "total",
60+
Help: "Total number of scrapes errors for Netgear system info stats.",
61+
},
62+
)
63+
64+
lastScrapeErrorMetric := prometheus.NewGauge(
65+
prometheus.GaugeOpts{
66+
Namespace: namespace,
67+
Subsystem: "",
68+
Name: "last_system_info_scrape_error",
69+
Help: "Whether the last scrape of Netgear system info stats resulted in an error (1 for error, 0 for success).",
70+
},
71+
)
72+
73+
lastScrapeTimestampMetric := prometheus.NewGauge(
74+
prometheus.GaugeOpts{
75+
Namespace: namespace,
76+
Subsystem: "",
77+
Name: "last_system_info_scrape_timestamp",
78+
Help: "Number of seconds since 1970 since last scrape of Netgear system info metrics.",
79+
},
80+
)
81+
82+
lastScrapeDurationSecondsMetric := prometheus.NewGauge(
83+
prometheus.GaugeOpts{
84+
Namespace: namespace,
85+
Subsystem: "",
86+
Name: "last_info_scrape_duration_seconds",
87+
Help: "Duration of the last scrape of Netgear system info stats.",
88+
},
89+
)
90+
91+
return &SystemInfo{
92+
namespace: namespace,
93+
client: client,
94+
metrics: metrics,
95+
96+
scrapesTotalMetric: scrapesTotalMetric,
97+
scrapeErrorsTotalMetric: scrapeErrorsTotalMetric,
98+
lastScrapeErrorMetric: lastScrapeErrorMetric,
99+
lastScrapeTimestampMetric: lastScrapeTimestampMetric,
100+
lastScrapeDurationSecondsMetric: lastScrapeDurationSecondsMetric,
101+
}
102+
}
103+
104+
func (c *SystemInfo) Collect(ch chan<- prometheus.Metric) {
105+
var begun = time.Now()
106+
107+
errorMetric := float64(0)
108+
stats, err := c.client.GetSystemInfo()
109+
if err != nil {
110+
log.Errorf("Error while collecting system info: %v", err)
111+
errorMetric = float64(1)
112+
c.scrapeErrorsTotalMetric.Inc()
113+
} else {
114+
/* Loop through the names we expect */
115+
for _, name := range SystemInfoFields {
116+
/* Check first that we got what we expect */
117+
if val, ok := stats[name]; ok {
118+
var metric float64
119+
metric, _ = strconv.ParseFloat(val, 64)
120+
121+
c.metrics[name].Set(metric)
122+
c.metrics[name].Collect(ch)
123+
} else {
124+
log.Warnf("System info stat named '%s' missing from results!", name)
125+
}
126+
}
127+
}
128+
129+
c.scrapeErrorsTotalMetric.Collect(ch)
130+
131+
c.scrapesTotalMetric.Inc()
132+
c.scrapesTotalMetric.Collect(ch)
133+
134+
c.lastScrapeErrorMetric.Set(errorMetric)
135+
c.lastScrapeErrorMetric.Collect(ch)
136+
137+
c.lastScrapeTimestampMetric.Set(float64(time.Now().Unix()))
138+
c.lastScrapeTimestampMetric.Collect(ch)
139+
140+
c.lastScrapeDurationSecondsMetric.Set(time.Since(begun).Seconds())
141+
c.lastScrapeDurationSecondsMetric.Collect(ch)
142+
}
143+
144+
func (c *SystemInfo) Describe(ch chan<- *prometheus.Desc) {
145+
for _, name := range SystemInfoFields {
146+
c.metrics[name].Describe(ch)
147+
}
148+
149+
c.scrapesTotalMetric.Describe(ch)
150+
c.scrapeErrorsTotalMetric.Describe(ch)
151+
c.lastScrapeErrorMetric.Describe(ch)
152+
c.lastScrapeTimestampMetric.Describe(ch)
153+
c.lastScrapeDurationSecondsMetric.Describe(ch)
154+
}

filters/collectors_filters.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import (
77
)
88

99
const (
10-
TrafficCollector = "Traffic"
11-
TrafficDeltaCollector = "TrafficDelta"
10+
ClientCollector = "Client"
11+
SystemInfoCollector = "SystemInfo"
12+
TrafficCollector = "Traffic"
1213
)
1314

1415
type CollectorsFilter struct {
@@ -20,10 +21,12 @@ func NewCollectorsFilter(filters []string) (*CollectorsFilter, error) {
2021

2122
for _, collectorName := range filters {
2223
switch strings.Trim(collectorName, " ") {
24+
case ClientCollector:
25+
collectorsEnabled[ClientCollector] = true
26+
case SystemInfoCollector:
27+
collectorsEnabled[SystemInfoCollector] = true
2328
case TrafficCollector:
2429
collectorsEnabled[TrafficCollector] = true
25-
case TrafficDeltaCollector:
26-
collectorsEnabled[TrafficDeltaCollector] = true
2730
default:
2831
return &CollectorsFilter{}, errors.New(fmt.Sprintf("Collector filter `%s` is not supported", collectorName))
2932
}

0 commit comments

Comments
 (0)