2018-07-16 13:08:18 +00:00
// Copyright 2018 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !nonetclass
// +build linux
package collector
import (
2021-03-03 07:57:16 +00:00
"errors"
2018-07-16 13:08:18 +00:00
"fmt"
2021-03-03 07:57:16 +00:00
"os"
2018-07-16 13:08:18 +00:00
"regexp"
2019-12-31 16:19:37 +00:00
"github.com/go-kit/kit/log"
2021-03-03 07:57:16 +00:00
"github.com/go-kit/kit/log/level"
2018-07-16 13:08:18 +00:00
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs/sysfs"
2019-12-31 16:19:37 +00:00
"gopkg.in/alecthomas/kingpin.v2"
2018-07-16 13:08:18 +00:00
)
var (
netclassIgnoredDevices = kingpin . Flag ( "collector.netclass.ignored-devices" , "Regexp of net devices to ignore for netclass collector." ) . Default ( "^$" ) . String ( )
2021-03-04 09:32:45 +00:00
netclassInvalidSpeed = kingpin . Flag ( "collector.netclass.ignore-invalid-speed" , "Ignore devices where the speed is invalid. This will be the default behavior in 2.x." ) . Bool ( )
2018-07-16 13:08:18 +00:00
)
type netClassCollector struct {
2019-04-10 16:16:12 +00:00
fs sysfs . FS
2018-07-16 13:08:18 +00:00
subsystem string
ignoredDevicesPattern * regexp . Regexp
metricDescs map [ string ] * prometheus . Desc
2019-12-31 16:19:37 +00:00
logger log . Logger
2018-07-16 13:08:18 +00:00
}
func init ( ) {
registerCollector ( "netclass" , defaultEnabled , NewNetClassCollector )
}
// NewNetClassCollector returns a new Collector exposing network class stats.
2019-12-31 16:19:37 +00:00
func NewNetClassCollector ( logger log . Logger ) ( Collector , error ) {
2019-04-10 16:16:12 +00:00
fs , err := sysfs . NewFS ( * sysPath )
if err != nil {
2019-11-29 13:51:31 +00:00
return nil , fmt . Errorf ( "failed to open sysfs: %w" , err )
2019-04-10 16:16:12 +00:00
}
2018-07-16 13:08:18 +00:00
pattern := regexp . MustCompile ( * netclassIgnoredDevices )
return & netClassCollector {
2019-04-10 16:16:12 +00:00
fs : fs ,
2018-07-16 13:08:18 +00:00
subsystem : "network" ,
ignoredDevicesPattern : pattern ,
metricDescs : map [ string ] * prometheus . Desc { } ,
2019-12-31 16:19:37 +00:00
logger : logger ,
2018-07-16 13:08:18 +00:00
} , nil
}
func ( c * netClassCollector ) Update ( ch chan <- prometheus . Metric ) error {
2019-04-10 16:16:12 +00:00
netClass , err := c . getNetClassInfo ( )
2018-07-16 13:08:18 +00:00
if err != nil {
2021-03-03 07:57:16 +00:00
if errors . Is ( err , os . ErrNotExist ) || errors . Is ( err , os . ErrPermission ) {
level . Debug ( c . logger ) . Log ( "msg" , "Could not read netclass file" , "err" , err )
return ErrNoData
}
2020-06-15 20:27:14 +00:00
return fmt . Errorf ( "could not get net class info: %w" , err )
2018-07-16 13:08:18 +00:00
}
for _ , ifaceInfo := range netClass {
upDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , c . subsystem , "up" ) ,
2019-02-07 14:59:32 +00:00
"Value is 1 if operstate is 'up', 0 otherwise." ,
[ ] string { "device" } ,
2018-07-16 13:08:18 +00:00
nil ,
)
upValue := 0.0
if ifaceInfo . OperState == "up" {
upValue = 1.0
}
2019-02-07 14:59:32 +00:00
ch <- prometheus . MustNewConstMetric ( upDesc , prometheus . GaugeValue , upValue , ifaceInfo . Name )
infoDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , c . subsystem , "info" ) ,
"Non-numeric data from /sys/class/net/<iface>, value is always 1." ,
[ ] string { "device" , "address" , "broadcast" , "duplex" , "operstate" , "ifalias" } ,
nil ,
)
infoValue := 1.0
ch <- prometheus . MustNewConstMetric ( infoDesc , prometheus . GaugeValue , infoValue , ifaceInfo . Name , ifaceInfo . Address , ifaceInfo . Broadcast , ifaceInfo . Duplex , ifaceInfo . OperState , ifaceInfo . IfAlias )
2018-07-16 13:08:18 +00:00
if ifaceInfo . AddrAssignType != nil {
pushMetric ( ch , c . subsystem , "address_assign_type" , * ifaceInfo . AddrAssignType , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . Carrier != nil {
pushMetric ( ch , c . subsystem , "carrier" , * ifaceInfo . Carrier , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . CarrierChanges != nil {
pushMetric ( ch , c . subsystem , "carrier_changes_total" , * ifaceInfo . CarrierChanges , ifaceInfo . Name , prometheus . CounterValue )
}
if ifaceInfo . CarrierUpCount != nil {
pushMetric ( ch , c . subsystem , "carrier_up_changes_total" , * ifaceInfo . CarrierUpCount , ifaceInfo . Name , prometheus . CounterValue )
}
if ifaceInfo . CarrierDownCount != nil {
pushMetric ( ch , c . subsystem , "carrier_down_changes_total" , * ifaceInfo . CarrierDownCount , ifaceInfo . Name , prometheus . CounterValue )
}
if ifaceInfo . DevID != nil {
pushMetric ( ch , c . subsystem , "device_id" , * ifaceInfo . DevID , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . Dormant != nil {
pushMetric ( ch , c . subsystem , "dormant" , * ifaceInfo . Dormant , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . Flags != nil {
pushMetric ( ch , c . subsystem , "flags" , * ifaceInfo . Flags , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . IfIndex != nil {
pushMetric ( ch , c . subsystem , "iface_id" , * ifaceInfo . IfIndex , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . IfLink != nil {
pushMetric ( ch , c . subsystem , "iface_link" , * ifaceInfo . IfLink , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . LinkMode != nil {
pushMetric ( ch , c . subsystem , "iface_link_mode" , * ifaceInfo . LinkMode , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . MTU != nil {
pushMetric ( ch , c . subsystem , "mtu_bytes" , * ifaceInfo . MTU , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . NameAssignType != nil {
pushMetric ( ch , c . subsystem , "name_assign_type" , * ifaceInfo . NameAssignType , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . NetDevGroup != nil {
pushMetric ( ch , c . subsystem , "net_dev_group" , * ifaceInfo . NetDevGroup , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . Speed != nil {
2021-03-04 09:32:45 +00:00
// Some devices return -1 if the speed is unknown.
if * ifaceInfo . Speed >= 0 || ! * netclassInvalidSpeed {
speedBytes := int64 ( * ifaceInfo . Speed * 1000 * 1000 / 8 )
pushMetric ( ch , c . subsystem , "speed_bytes" , speedBytes , ifaceInfo . Name , prometheus . GaugeValue )
}
2018-07-16 13:08:18 +00:00
}
if ifaceInfo . TxQueueLen != nil {
pushMetric ( ch , c . subsystem , "transmit_queue_length" , * ifaceInfo . TxQueueLen , ifaceInfo . Name , prometheus . GaugeValue )
}
if ifaceInfo . Type != nil {
pushMetric ( ch , c . subsystem , "protocol_type" , * ifaceInfo . Type , ifaceInfo . Name , prometheus . GaugeValue )
}
}
return nil
}
func pushMetric ( ch chan <- prometheus . Metric , subsystem string , name string , value int64 , ifaceName string , valueType prometheus . ValueType ) {
fieldDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , name ) ,
fmt . Sprintf ( "%s value of /sys/class/net/<iface>." , name ) ,
2019-02-06 19:02:48 +00:00
[ ] string { "device" } ,
2018-07-16 13:08:18 +00:00
nil ,
)
ch <- prometheus . MustNewConstMetric ( fieldDesc , valueType , float64 ( value ) , ifaceName )
}
2019-04-10 16:16:12 +00:00
func ( c * netClassCollector ) getNetClassInfo ( ) ( sysfs . NetClass , error ) {
2019-06-12 18:47:16 +00:00
netClass , err := c . fs . NetClass ( )
2018-07-16 13:08:18 +00:00
if err != nil {
2021-03-03 07:57:16 +00:00
return netClass , err
2018-07-16 13:08:18 +00:00
}
for device := range netClass {
2019-04-10 16:16:12 +00:00
if c . ignoredDevicesPattern . MatchString ( device ) {
2018-07-16 13:08:18 +00:00
delete ( netClass , device )
}
}
return netClass , nil
}