diff options
author | Jan Klat <jenik@klatys.cz> | 2018-07-16 15:08:18 +0200 |
---|---|---|
committer | Johannes 'fish' Ziemke <github@freigeist.org> | 2018-07-16 15:08:18 +0200 |
commit | c4102f117584f92e18e9612d9a9eecd0815e89bd (patch) | |
tree | 06e8fbb27352e471bfece0c5a7e9543745f2c3cb /collector/netclass_linux.go | |
parent | 09b4305090a6af1e69c528539fba63fc5ff781c6 (diff) | |
download | prometheus_node_collector-c4102f117584f92e18e9612d9a9eecd0815e89bd.tar.bz2 prometheus_node_collector-c4102f117584f92e18e9612d9a9eecd0815e89bd.tar.xz prometheus_node_collector-c4102f117584f92e18e9612d9a9eecd0815e89bd.zip |
Add sys/class/net parsing from procfs and expose its metrics (#851)
* add sys/class/net parsing from procfs and expose its metrics
Signed-off-by: Jan Klat <jenik@klatys.cz>
* change code to use int pointers per procfs change, move netclass to separate collector, change metric naming
Signed-off-by: Jan Klat <jenik@klatys.cz>
* bump year in licence, remove redundant newline, correct fixtures
Signed-off-by: Jan Klat <jenik@klatys.cz>
* fix style
Signed-off-by: Jan Klat <jenik@klatys.cz>
* change carrier changes to counter type
Signed-off-by: Jan Klat <jenik@klatys.cz>
* fix e2e output
Signed-off-by: Jan Klat <jenik@klatys.cz>
* add fixtures
Signed-off-by: Jan Klat <jenik@klatys.cz>
* update vendor, use fixtures correctly
Signed-off-by: Jan Klat <jenik@klatys.cz>
* change fixtures (device in /sys/class/net should be symlinked)
Signed-off-by: Jan Klat <jenik@klatys.cz>
* correct fixtures for 64k page, updated readme
Signed-off-by: Jan Klat <jenik@klatys.cz>
Diffstat (limited to 'collector/netclass_linux.go')
-rw-r--r-- | collector/netclass_linux.go | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/collector/netclass_linux.go b/collector/netclass_linux.go new file mode 100644 index 0000000..a71f302 --- /dev/null +++ b/collector/netclass_linux.go | |||
@@ -0,0 +1,173 @@ | |||
1 | // Copyright 2018 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 | // +build !nonetclass | ||
15 | // +build linux | ||
16 | |||
17 | package collector | ||
18 | |||
19 | import ( | ||
20 | "fmt" | ||
21 | "regexp" | ||
22 | |||
23 | "github.com/prometheus/client_golang/prometheus" | ||
24 | "github.com/prometheus/procfs/sysfs" | ||
25 | "gopkg.in/alecthomas/kingpin.v2" | ||
26 | ) | ||
27 | |||
28 | var ( | ||
29 | netclassIgnoredDevices = kingpin.Flag("collector.netclass.ignored-devices", "Regexp of net devices to ignore for netclass collector.").Default("^$").String() | ||
30 | ) | ||
31 | |||
32 | type netClassCollector struct { | ||
33 | subsystem string | ||
34 | ignoredDevicesPattern *regexp.Regexp | ||
35 | metricDescs map[string]*prometheus.Desc | ||
36 | } | ||
37 | |||
38 | func init() { | ||
39 | registerCollector("netclass", defaultEnabled, NewNetClassCollector) | ||
40 | } | ||
41 | |||
42 | // NewNetClassCollector returns a new Collector exposing network class stats. | ||
43 | func NewNetClassCollector() (Collector, error) { | ||
44 | pattern := regexp.MustCompile(*netclassIgnoredDevices) | ||
45 | return &netClassCollector{ | ||
46 | subsystem: "network", | ||
47 | ignoredDevicesPattern: pattern, | ||
48 | metricDescs: map[string]*prometheus.Desc{}, | ||
49 | }, nil | ||
50 | } | ||
51 | |||
52 | func (c *netClassCollector) Update(ch chan<- prometheus.Metric) error { | ||
53 | netClass, err := getNetClassInfo(c.ignoredDevicesPattern) | ||
54 | if err != nil { | ||
55 | return fmt.Errorf("could not get net class info: %s", err) | ||
56 | } | ||
57 | for _, ifaceInfo := range netClass { | ||
58 | upDesc := prometheus.NewDesc( | ||
59 | prometheus.BuildFQName(namespace, c.subsystem, "up"), | ||
60 | "Valid operstate for interface.", | ||
61 | []string{"interface", "address", "broadcast", "duplex", "operstate", "ifalias"}, | ||
62 | nil, | ||
63 | ) | ||
64 | upValue := 0.0 | ||
65 | if ifaceInfo.OperState == "up" { | ||
66 | upValue = 1.0 | ||
67 | } | ||
68 | |||
69 | ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, upValue, ifaceInfo.Name, ifaceInfo.Address, ifaceInfo.Broadcast, ifaceInfo.Duplex, ifaceInfo.OperState, ifaceInfo.IfAlias) | ||
70 | |||
71 | if ifaceInfo.AddrAssignType != nil { | ||
72 | pushMetric(ch, c.subsystem, "address_assign_type", *ifaceInfo.AddrAssignType, ifaceInfo.Name, prometheus.GaugeValue) | ||
73 | } | ||
74 | |||
75 | if ifaceInfo.Carrier != nil { | ||
76 | pushMetric(ch, c.subsystem, "carrier", *ifaceInfo.Carrier, ifaceInfo.Name, prometheus.GaugeValue) | ||
77 | } | ||
78 | |||
79 | if ifaceInfo.CarrierChanges != nil { | ||
80 | pushMetric(ch, c.subsystem, "carrier_changes_total", *ifaceInfo.CarrierChanges, ifaceInfo.Name, prometheus.CounterValue) | ||
81 | } | ||
82 | |||
83 | if ifaceInfo.CarrierUpCount != nil { | ||
84 | pushMetric(ch, c.subsystem, "carrier_up_changes_total", *ifaceInfo.CarrierUpCount, ifaceInfo.Name, prometheus.CounterValue) | ||
85 | } | ||
86 | |||
87 | if ifaceInfo.CarrierDownCount != nil { | ||
88 | pushMetric(ch, c.subsystem, "carrier_down_changes_total", *ifaceInfo.CarrierDownCount, ifaceInfo.Name, prometheus.CounterValue) | ||
89 | } | ||
90 | |||
91 | if ifaceInfo.DevID != nil { | ||
92 | pushMetric(ch, c.subsystem, "device_id", *ifaceInfo.DevID, ifaceInfo.Name, prometheus.GaugeValue) | ||
93 | } | ||
94 | |||
95 | if ifaceInfo.Dormant != nil { | ||
96 | pushMetric(ch, c.subsystem, "dormant", *ifaceInfo.Dormant, ifaceInfo.Name, prometheus.GaugeValue) | ||
97 | } | ||
98 | |||
99 | if ifaceInfo.Flags != nil { | ||
100 | pushMetric(ch, c.subsystem, "flags", *ifaceInfo.Flags, ifaceInfo.Name, prometheus.GaugeValue) | ||
101 | } | ||
102 | |||
103 | if ifaceInfo.IfIndex != nil { | ||
104 | pushMetric(ch, c.subsystem, "iface_id", *ifaceInfo.IfIndex, ifaceInfo.Name, prometheus.GaugeValue) | ||
105 | } | ||
106 | |||
107 | if ifaceInfo.IfLink != nil { | ||
108 | pushMetric(ch, c.subsystem, "iface_link", *ifaceInfo.IfLink, ifaceInfo.Name, prometheus.GaugeValue) | ||
109 | } | ||
110 | |||
111 | if ifaceInfo.LinkMode != nil { | ||
112 | pushMetric(ch, c.subsystem, "iface_link_mode", *ifaceInfo.LinkMode, ifaceInfo.Name, prometheus.GaugeValue) | ||
113 | } | ||
114 | |||
115 | if ifaceInfo.MTU != nil { | ||
116 | pushMetric(ch, c.subsystem, "mtu_bytes", *ifaceInfo.MTU, ifaceInfo.Name, prometheus.GaugeValue) | ||
117 | } | ||
118 | |||
119 | if ifaceInfo.NameAssignType != nil { | ||
120 | pushMetric(ch, c.subsystem, "name_assign_type", *ifaceInfo.NameAssignType, ifaceInfo.Name, prometheus.GaugeValue) | ||
121 | } | ||
122 | |||
123 | if ifaceInfo.NetDevGroup != nil { | ||
124 | pushMetric(ch, c.subsystem, "net_dev_group", *ifaceInfo.NetDevGroup, ifaceInfo.Name, prometheus.GaugeValue) | ||
125 | } | ||
126 | |||
127 | if ifaceInfo.Speed != nil { | ||
128 | speedBytes := int64(*ifaceInfo.Speed / 8 * 1000 * 1000) | ||
129 | pushMetric(ch, c.subsystem, "speed_bytes", speedBytes, ifaceInfo.Name, prometheus.GaugeValue) | ||
130 | } | ||
131 | |||
132 | if ifaceInfo.TxQueueLen != nil { | ||
133 | pushMetric(ch, c.subsystem, "transmit_queue_length", *ifaceInfo.TxQueueLen, ifaceInfo.Name, prometheus.GaugeValue) | ||
134 | } | ||
135 | |||
136 | if ifaceInfo.Type != nil { | ||
137 | pushMetric(ch, c.subsystem, "protocol_type", *ifaceInfo.Type, ifaceInfo.Name, prometheus.GaugeValue) | ||
138 | } | ||
139 | } | ||
140 | |||
141 | return nil | ||
142 | } | ||
143 | |||
144 | func pushMetric(ch chan<- prometheus.Metric, subsystem string, name string, value int64, ifaceName string, valueType prometheus.ValueType) { | ||
145 | fieldDesc := prometheus.NewDesc( | ||
146 | prometheus.BuildFQName(namespace, subsystem, name), | ||
147 | fmt.Sprintf("%s value of /sys/class/net/<iface>.", name), | ||
148 | []string{"interface"}, | ||
149 | nil, | ||
150 | ) | ||
151 | |||
152 | ch <- prometheus.MustNewConstMetric(fieldDesc, valueType, float64(value), ifaceName) | ||
153 | } | ||
154 | |||
155 | func getNetClassInfo(ignore *regexp.Regexp) (sysfs.NetClass, error) { | ||
156 | fs, err := sysfs.NewFS(*sysPath) | ||
157 | if err != nil { | ||
158 | return nil, err | ||
159 | } | ||
160 | netClass, err := fs.NewNetClass() | ||
161 | |||
162 | if err != nil { | ||
163 | return netClass, fmt.Errorf("error obtaining net class info: %s", err) | ||
164 | } | ||
165 | |||
166 | for device := range netClass { | ||
167 | if ignore.MatchString(device) { | ||
168 | delete(netClass, device) | ||
169 | } | ||
170 | } | ||
171 | |||
172 | return netClass, nil | ||
173 | } | ||