4141 ethtoolDeviceInclude = kingpin .Flag ("collector.ethtool.device-include" , "Regexp of ethtool devices to include (mutually exclusive to device-exclude)." ).String ()
4242 ethtoolDeviceExclude = kingpin .Flag ("collector.ethtool.device-exclude" , "Regexp of ethtool devices to exclude (mutually exclusive to device-include)." ).String ()
4343 ethtoolIncludedMetrics = kingpin .Flag ("collector.ethtool.metrics-include" , "Regexp of ethtool stats to include." ).Default (".*" ).String ()
44+ ethtoolAddIfAliasLabel = kingpin .Flag ("collector.ethtool.label-ifalias" , "Add ifalias label" ).Default ("false" ).Bool ()
4445 ethtoolReceivedRegex = regexp .MustCompile (`(^|_)rx(_|$)` )
4546 ethtoolTransmitRegex = regexp .MustCompile (`(^|_)tx(_|$)` )
4647)
@@ -78,6 +79,7 @@ type ethtoolCollector struct {
7879 infoDesc * prometheus.Desc
7980 metricsPattern * regexp.Regexp
8081 logger * slog.Logger
82+ ifAliasEnabled bool
8183}
8284
8385// makeEthtoolCollector is the internal constructor for EthtoolCollector.
@@ -94,6 +96,9 @@ func makeEthtoolCollector(logger *slog.Logger) (*ethtoolCollector, error) {
9496 return nil , fmt .Errorf ("failed to initialize ethtool library: %w" , err )
9597 }
9698
99+ deviceLabels := []string {"device" }
100+ infoDescHelp := "A metric with a constant '1' value labeled by bus_info, device, driver, expansion_rom_version, firmware_version, version."
101+
97102 if * ethtoolDeviceInclude != "" {
98103 logger .Info ("Parsed flag --collector.ethtool.device-include" , "flag" , * ethtoolDeviceInclude )
99104 }
@@ -103,6 +108,11 @@ func makeEthtoolCollector(logger *slog.Logger) (*ethtoolCollector, error) {
103108 if * ethtoolIncludedMetrics != "" {
104109 logger .Info ("Parsed flag --collector.ethtool.metrics-include" , "flag" , * ethtoolIncludedMetrics )
105110 }
111+ if * ethtoolAddIfAliasLabel {
112+ logger .Info ("Parsed flag --collector.ethtool.label-ifalias" , "flag" , * ethtoolAddIfAliasLabel )
113+ deviceLabels = []string {"device" , "ifalias" }
114+ infoDescHelp = "A metric with a constant '1' value labeled by bus_info, device, ifalias, driver, expansion_rom_version, firmware_version, version."
115+ }
106116
107117 // Pre-populate some common ethtool metrics.
108118 return & ethtoolCollector {
@@ -115,96 +125,96 @@ func makeEthtoolCollector(logger *slog.Logger) (*ethtoolCollector, error) {
115125 "rx_bytes" : prometheus .NewDesc (
116126 prometheus .BuildFQName (namespace , "ethtool" , "received_bytes_total" ),
117127 "Network interface bytes received" ,
118- [] string { "device" } , nil ,
128+ deviceLabels , nil ,
119129 ),
120130 "rx_dropped" : prometheus .NewDesc (
121131 prometheus .BuildFQName (namespace , "ethtool" , "received_dropped_total" ),
122132 "Number of received frames dropped" ,
123- [] string { "device" } , nil ,
133+ deviceLabels , nil ,
124134 ),
125135 "rx_errors" : prometheus .NewDesc (
126136 prometheus .BuildFQName (namespace , "ethtool" , "received_errors_total" ),
127137 "Number of received frames with errors" ,
128- [] string { "device" } , nil ,
138+ deviceLabels , nil ,
129139 ),
130140 "rx_packets" : prometheus .NewDesc (
131141 prometheus .BuildFQName (namespace , "ethtool" , "received_packets_total" ),
132142 "Network interface packets received" ,
133- [] string { "device" } , nil ,
143+ deviceLabels , nil ,
134144 ),
135145 "tx_bytes" : prometheus .NewDesc (
136146 prometheus .BuildFQName (namespace , "ethtool" , "transmitted_bytes_total" ),
137147 "Network interface bytes sent" ,
138- [] string { "device" } , nil ,
148+ deviceLabels , nil ,
139149 ),
140150 "tx_errors" : prometheus .NewDesc (
141151 prometheus .BuildFQName (namespace , "ethtool" , "transmitted_errors_total" ),
142152 "Number of sent frames with errors" ,
143- [] string { "device" } , nil ,
153+ deviceLabels , nil ,
144154 ),
145155 "tx_packets" : prometheus .NewDesc (
146156 prometheus .BuildFQName (namespace , "ethtool" , "transmitted_packets_total" ),
147157 "Network interface packets sent" ,
148- [] string { "device" } , nil ,
158+ deviceLabels , nil ,
149159 ),
150160
151161 // link info
152162 "supported_port" : prometheus .NewDesc (
153163 prometheus .BuildFQName (namespace , "network" , "supported_port_info" ),
154164 "Type of ports or PHYs supported by network device" ,
155- [] string { "device" , "type" } , nil ,
165+ append ( deviceLabels , "type" ) , nil ,
156166 ),
157167 "supported_speed" : prometheus .NewDesc (
158168 prometheus .BuildFQName (namespace , "network" , "supported_speed_bytes" ),
159169 "Combination of speeds and features supported by network device" ,
160- [] string { "device" , "duplex" , "mode" } , nil ,
170+ append ( deviceLabels , "duplex" , "mode" ) , nil ,
161171 ),
162172 "supported_autonegotiate" : prometheus .NewDesc (
163173 prometheus .BuildFQName (namespace , "network" , "autonegotiate_supported" ),
164174 "If this port device supports autonegotiate" ,
165- [] string { "device" } , nil ,
175+ deviceLabels , nil ,
166176 ),
167177 "supported_pause" : prometheus .NewDesc (
168178 prometheus .BuildFQName (namespace , "network" , "pause_supported" ),
169179 "If this port device supports pause frames" ,
170- [] string { "device" } , nil ,
180+ deviceLabels , nil ,
171181 ),
172182 "supported_asymmetricpause" : prometheus .NewDesc (
173183 prometheus .BuildFQName (namespace , "network" , "asymmetricpause_supported" ),
174184 "If this port device supports asymmetric pause frames" ,
175- [] string { "device" } , nil ,
185+ deviceLabels , nil ,
176186 ),
177187 "advertised_speed" : prometheus .NewDesc (
178188 prometheus .BuildFQName (namespace , "network" , "advertised_speed_bytes" ),
179189 "Combination of speeds and features offered by network device" ,
180- [] string { "device" , "duplex" , "mode" } , nil ,
190+ append ( deviceLabels , "duplex" , "mode" ) , nil ,
181191 ),
182192 "advertised_autonegotiate" : prometheus .NewDesc (
183193 prometheus .BuildFQName (namespace , "network" , "autonegotiate_advertised" ),
184194 "If this port device offers autonegotiate" ,
185- [] string { "device" } , nil ,
195+ deviceLabels , nil ,
186196 ),
187197 "advertised_pause" : prometheus .NewDesc (
188198 prometheus .BuildFQName (namespace , "network" , "pause_advertised" ),
189199 "If this port device offers pause capability" ,
190- [] string { "device" } , nil ,
200+ deviceLabels , nil ,
191201 ),
192202 "advertised_asymmetricpause" : prometheus .NewDesc (
193203 prometheus .BuildFQName (namespace , "network" , "asymmetricpause_advertised" ),
194204 "If this port device offers asymmetric pause capability" ,
195- [] string { "device" } , nil ,
205+ deviceLabels , nil ,
196206 ),
197207 "autonegotiate" : prometheus .NewDesc (
198208 prometheus .BuildFQName (namespace , "network" , "autonegotiate" ),
199209 "If this port is using autonegotiate" ,
200- [] string { "device" } , nil ,
210+ deviceLabels , nil ,
201211 ),
202212 },
203213 infoDesc : prometheus .NewDesc (
204- prometheus .BuildFQName (namespace , "ethtool" , "info" ),
205- "A metric with a constant '1' value labeled by bus_info, device, driver, expansion_rom_version, firmware_version, version." ,
206- []string {"bus_info" , "device" , "driver" , "expansion_rom_version" , "firmware_version" , "version" }, nil ,
214+ prometheus .BuildFQName (namespace , "ethtool" , "info" ), infoDescHelp ,
215+ append (append ([]string {"bus_info" }, deviceLabels ... ), "driver" , "expansion_rom_version" , "firmware_version" , "version" ), nil ,
207216 ),
217+ ifAliasEnabled : * ethtoolAddIfAliasLabel ,
208218 }, nil
209219}
210220
@@ -225,10 +235,24 @@ func NewEthtoolCollector(logger *slog.Logger) (Collector, error) {
225235 return makeEthtoolCollector (logger )
226236}
227237
238+ func (c * ethtoolCollector ) deviceLabelValues (device , ifAlias string ) []string {
239+ if c .ifAliasEnabled {
240+ return []string {device , ifAlias }
241+ }
242+ return []string {device }
243+ }
244+
245+ func (c * ethtoolCollector ) deviceLabelNames () []string {
246+ if c .ifAliasEnabled {
247+ return []string {"device" , "ifalias" }
248+ }
249+ return []string {"device" }
250+ }
251+
228252// updatePortCapabilities generates metrics for autonegotiate, pause and asymmetricpause.
229253// The bit offsets here correspond to ethtool_link_mode_bit_indices in linux/include/uapi/linux/ethtool.h
230254// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/ethtool.h
231- func (c * ethtoolCollector ) updatePortCapabilities (ch chan <- prometheus.Metric , prefix string , device string , linkModes uint32 ) {
255+ func (c * ethtoolCollector ) updatePortCapabilities (ch chan <- prometheus.Metric , prefix string , device string , ifAlias string , linkModes uint32 ) {
232256 var (
233257 autonegotiate = 0.0
234258 pause = 0.0
@@ -243,15 +267,15 @@ func (c *ethtoolCollector) updatePortCapabilities(ch chan<- prometheus.Metric, p
243267 if linkModes & (1 << unix .ETHTOOL_LINK_MODE_Asym_Pause_BIT ) != 0 {
244268 asymmetricPause = 1.0
245269 }
246- ch <- prometheus .MustNewConstMetric (c .entry (fmt .Sprintf ("%s_autonegotiate" , prefix )), prometheus .GaugeValue , autonegotiate , device )
247- ch <- prometheus .MustNewConstMetric (c .entry (fmt .Sprintf ("%s_pause" , prefix )), prometheus .GaugeValue , pause , device )
248- ch <- prometheus .MustNewConstMetric (c .entry (fmt .Sprintf ("%s_asymmetricpause" , prefix )), prometheus .GaugeValue , asymmetricPause , device )
270+ ch <- prometheus .MustNewConstMetric (c .entry (fmt .Sprintf ("%s_autonegotiate" , prefix )), prometheus .GaugeValue , autonegotiate , c . deviceLabelValues ( device , ifAlias ) ... )
271+ ch <- prometheus .MustNewConstMetric (c .entry (fmt .Sprintf ("%s_pause" , prefix )), prometheus .GaugeValue , pause , c . deviceLabelValues ( device , ifAlias ) ... )
272+ ch <- prometheus .MustNewConstMetric (c .entry (fmt .Sprintf ("%s_asymmetricpause" , prefix )), prometheus .GaugeValue , asymmetricPause , c . deviceLabelValues ( device , ifAlias ) ... )
249273}
250274
251275// updatePortInfo generates port type metrics to indicate if the network devices supports Twisted Pair, optical fiber, etc.
252276// The bit offsets here correspond to ethtool_link_mode_bit_indices in linux/include/uapi/linux/ethtool.h
253277// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/ethtool.h
254- func (c * ethtoolCollector ) updatePortInfo (ch chan <- prometheus.Metric , device string , linkModes uint32 ) {
278+ func (c * ethtoolCollector ) updatePortInfo (ch chan <- prometheus.Metric , device string , ifAlias string , linkModes uint32 ) {
255279 for name , bit := range map [string ]int {
256280 "TP" : unix .ETHTOOL_LINK_MODE_TP_BIT ,
257281 "AUI" : unix .ETHTOOL_LINK_MODE_AUI_BIT ,
@@ -261,7 +285,7 @@ func (c *ethtoolCollector) updatePortInfo(ch chan<- prometheus.Metric, device st
261285 "Backplane" : unix .ETHTOOL_LINK_MODE_Backplane_BIT ,
262286 } {
263287 if linkModes & (1 << bit ) != 0 {
264- ch <- prometheus .MustNewConstMetric (c .entry ("supported_port" ), prometheus .GaugeValue , 1.0 , device , name )
288+ ch <- prometheus .MustNewConstMetric (c .entry ("supported_port" ), prometheus .GaugeValue , 1.0 , append ( c . deviceLabelValues ( device , ifAlias ), name ) ... )
265289 }
266290
267291 }
@@ -270,7 +294,7 @@ func (c *ethtoolCollector) updatePortInfo(ch chan<- prometheus.Metric, device st
270294// updateSpeeds generates metrics corresponding to the speeds and duplex modes supported or advertised by the network device.
271295// The bit offsets here correspond to ethtool_link_mode_bit_indices in linux/include/uapi/linux/ethtool.h
272296// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/ethtool.h
273- func (c * ethtoolCollector ) updateSpeeds (ch chan <- prometheus.Metric , prefix string , device string , linkModes uint32 ) {
297+ func (c * ethtoolCollector ) updateSpeeds (ch chan <- prometheus.Metric , prefix string , device string , ifAlias string , linkModes uint32 ) {
274298 linkMode := fmt .Sprintf ("%s_speed" , prefix )
275299 const (
276300 full = "full"
@@ -365,13 +389,13 @@ func (c *ethtoolCollector) updateSpeeds(ch chan<- prometheus.Metric, prefix stri
365389 } {
366390 if linkModes & (1 << bit ) != 0 {
367391 ch <- prometheus .MustNewConstMetric (c .entry (linkMode ), prometheus .GaugeValue ,
368- float64 (labels .speed )* Mbps , device , labels .duplex , fmt .Sprintf ("%dbase%s" , labels .speed , labels .phy ))
392+ float64 (labels .speed )* Mbps , append ( c . deviceLabelValues ( device , ifAlias ), labels .duplex , fmt .Sprintf ("%dbase%s" , labels .speed , labels .phy )) ... )
369393 }
370394 }
371395}
372396
373397func (c * ethtoolCollector ) Update (ch chan <- prometheus.Metric ) error {
374- netClass , err := c .fs .NetClassDevices ()
398+ netClass , err := c .fs .NetClass ()
375399 if err != nil {
376400 if errors .Is (err , os .ErrNotExist ) || errors .Is (err , os .ErrPermission ) {
377401 c .logger .Debug ("Could not read netclass file" , "err" , err )
@@ -384,7 +408,7 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
384408 return fmt .Errorf ("no network devices found" )
385409 }
386410
387- for _ , device := range netClass {
411+ for device , params := range netClass {
388412 var stats map [string ]uint64
389413 var err error
390414
@@ -394,12 +418,13 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
394418
395419 linkInfo , err := c .ethtool .LinkInfo (device )
396420 if err == nil {
397- c .updateSpeeds (ch , "supported" , device , linkInfo .Supported )
398- c .updatePortInfo (ch , device , linkInfo .Supported )
399- c .updatePortCapabilities (ch , "supported" , device , linkInfo .Supported )
400- c .updateSpeeds (ch , "advertised" , device , linkInfo .Advertising )
401- c .updatePortCapabilities (ch , "advertised" , device , linkInfo .Advertising )
402- ch <- prometheus .MustNewConstMetric (c .entry ("autonegotiate" ), prometheus .GaugeValue , float64 (linkInfo .Autoneg ), device )
421+ c .updateSpeeds (ch , "supported" , device , params .IfAlias , linkInfo .Supported )
422+ c .updatePortInfo (ch , device , params .IfAlias , linkInfo .Supported )
423+ c .updatePortCapabilities (ch , "supported" , device , params .IfAlias , linkInfo .Supported )
424+ c .updateSpeeds (ch , "advertised" , device , params .IfAlias , linkInfo .Advertising )
425+ c .updatePortCapabilities (ch , "advertised" , device , params .IfAlias , linkInfo .Advertising )
426+ ch <- prometheus .MustNewConstMetric (c .entry ("autonegotiate" ), prometheus .GaugeValue , float64 (linkInfo .Autoneg ),
427+ c .deviceLabelValues (device , params .IfAlias )... )
403428 } else {
404429 if errno , ok := err .(syscall.Errno ); ok {
405430 if err == unix .EOPNOTSUPP {
@@ -416,7 +441,7 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
416441
417442 if err == nil {
418443 ch <- prometheus .MustNewConstMetric (c .infoDesc , prometheus .GaugeValue , 1.0 ,
419- drvInfo .BusInfo , device , drvInfo .Driver , drvInfo .EromVersion , drvInfo .FwVersion , drvInfo .Version )
444+ append ( append ([] string { drvInfo .BusInfo }, c . deviceLabelValues ( device , params . IfAlias ) ... ), drvInfo .Driver , drvInfo .EromVersion , drvInfo .FwVersion , drvInfo .Version ) ... )
420445 } else {
421446 if errno , ok := err .(syscall.Errno ); ok {
422447 if err == unix .EOPNOTSUPP {
@@ -491,7 +516,7 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
491516 // Check to see if this metric exists; if not then create it and store it in c.entries.
492517 entry := c .entryWithCreate (metric , metricFQName )
493518 ch <- prometheus .MustNewConstMetric (
494- entry , prometheus .UntypedValue , float64 (val ), device )
519+ entry , prometheus .UntypedValue , float64 (val ), c . deviceLabelValues ( device , params . IfAlias ) ... )
495520 }
496521 }
497522
@@ -506,7 +531,7 @@ func (c *ethtoolCollector) entryWithCreate(key, metricFQName string) *prometheus
506531 c .entries [key ] = prometheus .NewDesc (
507532 metricFQName ,
508533 fmt .Sprintf ("Network interface %s" , key ),
509- [] string { "device" } , nil ,
534+ c . deviceLabelNames () , nil ,
510535 )
511536 }
512537
0 commit comments