mirror of
https://github.com/kubernetes/node-problem-detector.git
synced 2026-03-02 17:50:34 +00:00
Merge pull request #594 from oif/chore/optimize-netcollector-implementation
optimize netcollector implementation and custom `/proc` mount path
This commit is contained in:
@@ -46,13 +46,17 @@ type cpuCollector struct {
|
||||
mSystemInterruptsTotal *metrics.Int64Metric
|
||||
mSystemCPUStat *metrics.Float64Metric // per-cpu time from /proc/stats
|
||||
|
||||
config *ssmtypes.CPUStatsConfig
|
||||
config *ssmtypes.CPUStatsConfig
|
||||
procPath string
|
||||
|
||||
lastUsageTime map[string]float64
|
||||
}
|
||||
|
||||
func NewCPUCollectorOrDie(cpuConfig *ssmtypes.CPUStatsConfig) *cpuCollector {
|
||||
cc := cpuCollector{config: cpuConfig}
|
||||
func NewCPUCollectorOrDie(cpuConfig *ssmtypes.CPUStatsConfig, procPath string) *cpuCollector {
|
||||
cc := cpuCollector{
|
||||
config: cpuConfig,
|
||||
procPath: procPath,
|
||||
}
|
||||
|
||||
var err error
|
||||
cc.mRunnableTaskCount, err = metrics.NewFloat64Metric(
|
||||
|
||||
@@ -52,7 +52,6 @@ func (cc *cpuCollector) recordLoad() {
|
||||
}
|
||||
|
||||
func (cc *cpuCollector) recordSystemStats() {
|
||||
|
||||
// don't collect the load metrics if the configs are not present.
|
||||
if cc.mSystemCPUStat == nil && cc.mSystemInterruptsTotal == nil &&
|
||||
cc.mSystemProcessesTotal == nil && cc.mSystemProcsBlocked == nil &&
|
||||
@@ -60,7 +59,7 @@ func (cc *cpuCollector) recordSystemStats() {
|
||||
return
|
||||
}
|
||||
|
||||
fs, err := procfs.NewFS("/proc")
|
||||
fs, err := procfs.NewFS(cc.procPath)
|
||||
stats, err := fs.Stat()
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to retrieve cpu/process stats: %v", err)
|
||||
|
||||
@@ -67,6 +67,6 @@ func TestCpuCollector(t *testing.T) {
|
||||
if err := json.Unmarshal([]byte(fakeCPUConfig), cfg); err != nil {
|
||||
t.Fatalf("cannot load cpu config: %s", err)
|
||||
}
|
||||
mc := NewCPUCollectorOrDie(cfg)
|
||||
mc := NewCPUCollectorOrDie(cfg, "/proc")
|
||||
mc.collect()
|
||||
}
|
||||
|
||||
@@ -17,268 +17,199 @@ limitations under the License.
|
||||
package systemstatsmonitor
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"github.com/prometheus/procfs"
|
||||
"fmt"
|
||||
|
||||
ssmtypes "k8s.io/node-problem-detector/pkg/systemstatsmonitor/types"
|
||||
"k8s.io/node-problem-detector/pkg/util/metrics"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/prometheus/procfs"
|
||||
)
|
||||
|
||||
type netCollector struct {
|
||||
mNetDevRxBytes *metrics.Int64Metric
|
||||
mNetDevRxPackets *metrics.Int64Metric
|
||||
mNetDevRxErrors *metrics.Int64Metric
|
||||
mNetDevRxDropped *metrics.Int64Metric
|
||||
mNetDevRxFifo *metrics.Int64Metric
|
||||
mNetDevRxFrame *metrics.Int64Metric
|
||||
mNetDevRxCompressed *metrics.Int64Metric
|
||||
mNetDevRxMulticast *metrics.Int64Metric
|
||||
mNetDevTxBytes *metrics.Int64Metric
|
||||
mNetDevTxPackets *metrics.Int64Metric
|
||||
mNetDevTxErrors *metrics.Int64Metric
|
||||
mNetDevTxDropped *metrics.Int64Metric
|
||||
mNetDevTxFifo *metrics.Int64Metric
|
||||
mNetDevTxCollisions *metrics.Int64Metric
|
||||
mNetDevTxCarrier *metrics.Int64Metric
|
||||
mNetDevTxCompressed *metrics.Int64Metric
|
||||
|
||||
config *ssmtypes.NetStatsConfig
|
||||
config *ssmtypes.NetStatsConfig
|
||||
procPath string
|
||||
recorder *ifaceStatRecorder
|
||||
}
|
||||
|
||||
func NewNetCollectorOrDie(netConfig *ssmtypes.NetStatsConfig) *netCollector {
|
||||
nc := netCollector{config: netConfig}
|
||||
func NewNetCollectorOrDie(netConfig *ssmtypes.NetStatsConfig, procPath string) *netCollector {
|
||||
nc := netCollector{
|
||||
config: netConfig,
|
||||
procPath: procPath,
|
||||
recorder: newIfaceStatRecorder(),
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
nc.mNetDevRxBytes, err = metrics.NewInt64Metric(
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevRxBytes,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevRxBytes)].DisplayName,
|
||||
"Cumulative count of bytes received.",
|
||||
"Byte",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevRxBytes, err)
|
||||
}
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.RxBytes)
|
||||
},
|
||||
)
|
||||
|
||||
nc.mNetDevRxPackets, err = metrics.NewInt64Metric(
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevRxPackets,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevRxPackets)].DisplayName,
|
||||
"Cumulative count of packets received.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevRxPackets, err)
|
||||
}
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.RxPackets)
|
||||
},
|
||||
)
|
||||
|
||||
nc.mNetDevRxErrors, err = metrics.NewInt64Metric(
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevRxErrors,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevRxErrors)].DisplayName,
|
||||
"Cumulative count of receive errors encountered.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevRxErrors, err)
|
||||
}
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.RxErrors)
|
||||
},
|
||||
)
|
||||
|
||||
nc.mNetDevRxDropped, err = metrics.NewInt64Metric(
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevRxDropped,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevRxDropped)].DisplayName,
|
||||
"Cumulative count of packets dropped while receiving.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevRxDropped, err)
|
||||
}
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.RxDropped)
|
||||
},
|
||||
)
|
||||
|
||||
nc.mNetDevRxFifo, err = metrics.NewInt64Metric(
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevRxFifo,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevRxFifo)].DisplayName,
|
||||
"Cumulative count of FIFO buffer errors.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevRxFifo, err)
|
||||
}
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.RxFIFO)
|
||||
},
|
||||
)
|
||||
|
||||
nc.mNetDevRxFrame, err = metrics.NewInt64Metric(
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevRxFrame,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevRxFrame)].DisplayName,
|
||||
"Cumulative count of packet framing errors.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevRxFrame, err)
|
||||
}
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.RxFrame)
|
||||
},
|
||||
)
|
||||
|
||||
nc.mNetDevRxCompressed, err = metrics.NewInt64Metric(
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevRxCompressed,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevRxCompressed)].DisplayName,
|
||||
"Cumulative count of compressed packets received by the device driver.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevRxCompressed, err)
|
||||
}
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.RxCompressed)
|
||||
},
|
||||
)
|
||||
|
||||
nc.mNetDevRxMulticast, err = metrics.NewInt64Metric(
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevRxMulticast,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevRxMulticast)].DisplayName,
|
||||
"Cumulative count of multicast frames received by the device driver.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevRxMulticast, err)
|
||||
}
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.RxMulticast)
|
||||
},
|
||||
)
|
||||
|
||||
nc.mNetDevTxBytes, err = metrics.NewInt64Metric(
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevTxBytes,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevTxBytes)].DisplayName,
|
||||
"Cumulative count of bytes transmitted.",
|
||||
"Byte",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevTxBytes, err)
|
||||
}
|
||||
|
||||
nc.mNetDevTxPackets, err = metrics.NewInt64Metric(
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.TxBytes)
|
||||
},
|
||||
)
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevTxPackets,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevTxPackets)].DisplayName,
|
||||
"Cumulative count of packets transmitted.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevTxPackets, err)
|
||||
}
|
||||
|
||||
nc.mNetDevTxErrors, err = metrics.NewInt64Metric(
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.TxPackets)
|
||||
},
|
||||
)
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevTxErrors,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevTxErrors)].DisplayName,
|
||||
"Cumulative count of transmit errors encountered.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevTxErrors, err)
|
||||
}
|
||||
|
||||
nc.mNetDevTxDropped, err = metrics.NewInt64Metric(
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.TxErrors)
|
||||
},
|
||||
)
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevTxDropped,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevTxDropped)].DisplayName,
|
||||
"Cumulative count of packets dropped while transmitting.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevTxDropped, err)
|
||||
}
|
||||
|
||||
nc.mNetDevTxFifo, err = metrics.NewInt64Metric(
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.TxDropped)
|
||||
},
|
||||
)
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevTxFifo,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevTxFifo)].DisplayName,
|
||||
"Cumulative count of FIFO buffer errors.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevTxFifo, err)
|
||||
}
|
||||
|
||||
nc.mNetDevTxCollisions, err = metrics.NewInt64Metric(
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.TxFIFO)
|
||||
},
|
||||
)
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevTxCollisions,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevTxCollisions)].DisplayName,
|
||||
"Cumulative count of collisions detected on the interface.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevTxCollisions, err)
|
||||
}
|
||||
|
||||
nc.mNetDevTxCarrier, err = metrics.NewInt64Metric(
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.TxCollisions)
|
||||
},
|
||||
)
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevTxCarrier,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevTxCarrier)].DisplayName,
|
||||
"Cumulative count of carrier losses detected by the device driver.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevTxCarrier, err)
|
||||
}
|
||||
|
||||
nc.mNetDevTxCompressed, err = metrics.NewInt64Metric(
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.TxCarrier)
|
||||
},
|
||||
)
|
||||
nc.mustRegisterMetric(
|
||||
metrics.NetDevTxCompressed,
|
||||
netConfig.MetricsConfigs[string(metrics.NetDevTxCompressed)].DisplayName,
|
||||
"Cumulative count of compressed packets transmitted by the device driver.",
|
||||
"1",
|
||||
metrics.Sum,
|
||||
[]string{interfaceNameLabel})
|
||||
if err != nil {
|
||||
glog.Fatalf("Error initializing metric for %q: %v", metrics.NetDevTxCompressed, err)
|
||||
}
|
||||
func(stat procfs.NetDevLine) int64 {
|
||||
return int64(stat.TxCompressed)
|
||||
},
|
||||
)
|
||||
|
||||
return &nc
|
||||
}
|
||||
|
||||
func (nc *netCollector) recordNetDev() {
|
||||
if nc.mNetDevRxBytes == nil {
|
||||
return
|
||||
func (nc *netCollector) mustRegisterMetric(metricID metrics.MetricID, description, unit string,
|
||||
aggregation metrics.Aggregation, exporter func(stat procfs.NetDevLine) int64) {
|
||||
metricConfig, ok := nc.config.MetricsConfigs[string(metricID)]
|
||||
if !ok {
|
||||
glog.Fatalf("Metric config `%q` not found", metricID)
|
||||
}
|
||||
if nc.mNetDevRxPackets == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevRxErrors == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevRxDropped == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevRxFifo == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevRxFrame == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevRxCompressed == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevRxMulticast == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevTxBytes == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevTxPackets == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevTxErrors == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevTxDropped == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevTxFifo == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevTxCollisions == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevTxCarrier == nil {
|
||||
return
|
||||
}
|
||||
if nc.mNetDevTxCompressed == nil {
|
||||
return
|
||||
err := nc.recorder.Register(metricID, metricConfig.DisplayName, description, unit,
|
||||
aggregation, []string{interfaceNameLabel}, exporter)
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to initialize metric %q: %v", metricID, err)
|
||||
}
|
||||
}
|
||||
|
||||
fs, err := procfs.NewFS("/proc")
|
||||
func (nc *netCollector) recordNetDev() {
|
||||
fs, err := procfs.NewFS(nc.procPath)
|
||||
stats, err := fs.NetDev()
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to retrieve net dev stat: %v", err)
|
||||
@@ -289,22 +220,7 @@ func (nc *netCollector) recordNetDev() {
|
||||
tags := map[string]string{}
|
||||
tags[interfaceNameLabel] = iface
|
||||
|
||||
nc.mNetDevRxBytes.Record(tags, int64(ifaceStats.RxBytes))
|
||||
nc.mNetDevRxPackets.Record(tags, int64(ifaceStats.RxPackets))
|
||||
nc.mNetDevRxErrors.Record(tags, int64(ifaceStats.RxErrors))
|
||||
nc.mNetDevRxDropped.Record(tags, int64(ifaceStats.RxDropped))
|
||||
nc.mNetDevRxFifo.Record(tags, int64(ifaceStats.RxFIFO))
|
||||
nc.mNetDevRxFrame.Record(tags, int64(ifaceStats.RxFrame))
|
||||
nc.mNetDevRxCompressed.Record(tags, int64(ifaceStats.RxCompressed))
|
||||
nc.mNetDevRxMulticast.Record(tags, int64(ifaceStats.RxMulticast))
|
||||
nc.mNetDevTxBytes.Record(tags, int64(ifaceStats.TxBytes))
|
||||
nc.mNetDevTxPackets.Record(tags, int64(ifaceStats.TxPackets))
|
||||
nc.mNetDevTxErrors.Record(tags, int64(ifaceStats.TxErrors))
|
||||
nc.mNetDevTxDropped.Record(tags, int64(ifaceStats.TxDropped))
|
||||
nc.mNetDevTxFifo.Record(tags, int64(ifaceStats.TxFIFO))
|
||||
nc.mNetDevTxCollisions.Record(tags, int64(ifaceStats.TxCollisions))
|
||||
nc.mNetDevTxCarrier.Record(tags, int64(ifaceStats.TxCarrier))
|
||||
nc.mNetDevTxCompressed.Record(tags, int64(ifaceStats.TxCompressed))
|
||||
nc.recorder.RecordWithSameTags(ifaceStats, tags)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,3 +231,43 @@ func (nc *netCollector) collect() {
|
||||
|
||||
nc.recordNetDev()
|
||||
}
|
||||
|
||||
// TODO(@oif): Maybe implements a generic recorder
|
||||
type ifaceStatRecorder struct {
|
||||
collectors map[metrics.MetricID]ifaceStatCollector
|
||||
}
|
||||
|
||||
func newIfaceStatRecorder() *ifaceStatRecorder {
|
||||
return &ifaceStatRecorder{collectors: make(map[metrics.MetricID]ifaceStatCollector)}
|
||||
}
|
||||
|
||||
func (r *ifaceStatRecorder) Register(metricID metrics.MetricID, viewName string, description string,
|
||||
unit string, aggregation metrics.Aggregation, tagNames []string, exporter func(procfs.NetDevLine) int64) error {
|
||||
if _, ok := r.collectors[metricID]; ok {
|
||||
// Check duplication
|
||||
return fmt.Errorf("metric %q already registered", metricID)
|
||||
}
|
||||
metric, err := metrics.NewInt64Metric(metricID, viewName, description, unit, aggregation, tagNames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.collectors[metricID] = ifaceStatCollector{
|
||||
metric: metric,
|
||||
exporter: exporter,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r ifaceStatRecorder) RecordWithSameTags(stat procfs.NetDevLine, tags map[string]string) {
|
||||
// Range all registered collector and record its measurement with same tags
|
||||
for metricID, collector := range r.collectors {
|
||||
measurement := collector.exporter(stat)
|
||||
collector.metric.Record(tags, measurement)
|
||||
glog.V(6).Infof("Metric %q record measurement %d with tags %v", metricID, measurement, tags)
|
||||
}
|
||||
}
|
||||
|
||||
type ifaceStatCollector struct {
|
||||
metric *metrics.Int64Metric
|
||||
exporter func(procfs.NetDevLine) int64
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package systemstatsmonitor
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -27,11 +28,15 @@ import (
|
||||
|
||||
type osFeatureCollector struct {
|
||||
config *ssmtypes.OSFeatureStatsConfig
|
||||
procPath string
|
||||
osFeature *metrics.Int64Metric
|
||||
}
|
||||
|
||||
func NewOsFeatureCollectorOrDie(osFeatureConfig *ssmtypes.OSFeatureStatsConfig) *osFeatureCollector {
|
||||
oc := osFeatureCollector{config: osFeatureConfig}
|
||||
func NewOsFeatureCollectorOrDie(osFeatureConfig *ssmtypes.OSFeatureStatsConfig, procPath string) *osFeatureCollector {
|
||||
oc := osFeatureCollector{
|
||||
config: osFeatureConfig,
|
||||
procPath: procPath,
|
||||
}
|
||||
var err error
|
||||
// Use metrics.Last aggregation method to ensure the metric is a guage metric.
|
||||
if osFeatureConfig.MetricsConfigs["system/os_feature"].DisplayName != "" {
|
||||
@@ -145,12 +150,12 @@ func (ofc *osFeatureCollector) collect() {
|
||||
if ofc == nil || ofc.osFeature == nil {
|
||||
return
|
||||
}
|
||||
cmdlineArgs, err := system.CmdlineArgs()
|
||||
cmdlineArgs, err := system.CmdlineArgs(filepath.Join(ofc.procPath, "/cmdline"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Error retrieving cmdline args: %v", err)
|
||||
}
|
||||
ofc.recordFeaturesFromCmdline(cmdlineArgs)
|
||||
modules, err := system.Modules()
|
||||
modules, err := system.Modules(filepath.Join(ofc.procPath, "/modules"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Error retrieving kernel modules: %v", err)
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func NewSystemStatsMonitorOrDie(configPath string) types.Monitor {
|
||||
}
|
||||
|
||||
if len(ssm.config.CPUConfig.MetricsConfigs) > 0 {
|
||||
ssm.cpuCollector = NewCPUCollectorOrDie(&ssm.config.CPUConfig)
|
||||
ssm.cpuCollector = NewCPUCollectorOrDie(&ssm.config.CPUConfig, ssm.config.ProcPath)
|
||||
}
|
||||
if len(ssm.config.DiskConfig.MetricsConfigs) > 0 {
|
||||
ssm.diskCollector = NewDiskCollectorOrDie(&ssm.config.DiskConfig)
|
||||
@@ -96,10 +96,10 @@ func NewSystemStatsMonitorOrDie(configPath string) types.Monitor {
|
||||
ssm.config.OsFeatureConfig.KnownModulesConfigPath = filepath.Join(filepath.Dir(configPath),
|
||||
ssm.config.OsFeatureConfig.KnownModulesConfigPath)
|
||||
}
|
||||
ssm.osFeatureCollector = NewOsFeatureCollectorOrDie(&ssm.config.OsFeatureConfig)
|
||||
ssm.osFeatureCollector = NewOsFeatureCollectorOrDie(&ssm.config.OsFeatureConfig, ssm.config.ProcPath)
|
||||
}
|
||||
if len(ssm.config.NetConfig.MetricsConfigs) > 0 {
|
||||
ssm.netCollector = NewNetCollectorOrDie(&ssm.config.NetConfig)
|
||||
ssm.netCollector = NewNetCollectorOrDie(&ssm.config.NetConfig, ssm.config.ProcPath)
|
||||
}
|
||||
return &ssm
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -25,6 +26,7 @@ var (
|
||||
defaultInvokeIntervalString = (60 * time.Second).String()
|
||||
defaultlsblkTimeoutString = (5 * time.Second).String()
|
||||
defaultKnownModulesConfigPath = "guestosconfig/known-modules.json"
|
||||
defaultProcPath = "/proc"
|
||||
)
|
||||
|
||||
type MetricConfig struct {
|
||||
@@ -69,6 +71,7 @@ type SystemStatsConfig struct {
|
||||
NetConfig NetStatsConfig `json:"net"`
|
||||
InvokeIntervalString string `json:"invokeInterval"`
|
||||
InvokeInterval time.Duration `json:"-"`
|
||||
ProcPath string `json:"procPath"`
|
||||
}
|
||||
|
||||
// ApplyConfiguration applies default configurations.
|
||||
@@ -76,6 +79,9 @@ func (ssc *SystemStatsConfig) ApplyConfiguration() error {
|
||||
if ssc.InvokeIntervalString == "" {
|
||||
ssc.InvokeIntervalString = defaultInvokeIntervalString
|
||||
}
|
||||
if ssc.ProcPath == "" {
|
||||
ssc.ProcPath = defaultProcPath
|
||||
}
|
||||
if ssc.DiskConfig.LsblkTimeoutString == "" {
|
||||
ssc.DiskConfig.LsblkTimeoutString = defaultlsblkTimeoutString
|
||||
}
|
||||
@@ -101,6 +107,9 @@ func (ssc *SystemStatsConfig) Validate() error {
|
||||
if ssc.InvokeInterval <= time.Duration(0) {
|
||||
return fmt.Errorf("InvokeInterval %v must be above 0s", ssc.InvokeInterval)
|
||||
}
|
||||
if _, err := os.Stat(ssc.ProcPath); err != nil {
|
||||
return fmt.Errorf("ProcPath %v check failed: %s", ssc.ProcPath, err)
|
||||
}
|
||||
if ssc.DiskConfig.LsblkTimeout <= time.Duration(0) {
|
||||
return fmt.Errorf("LsblkTimeout %v must be above 0s", ssc.DiskConfig.LsblkTimeout)
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ func TestApplyConfiguration(t *testing.T) {
|
||||
},
|
||||
InvokeIntervalString: "60s",
|
||||
InvokeInterval: 60 * time.Second,
|
||||
ProcPath: defaultProcPath,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -66,6 +67,7 @@ func TestApplyConfiguration(t *testing.T) {
|
||||
},
|
||||
InvokeIntervalString: "1m0s",
|
||||
InvokeInterval: 60 * time.Second,
|
||||
ProcPath: defaultProcPath,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -19,8 +19,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var cmdlineFilePath = "/proc/cmdline"
|
||||
|
||||
type CmdlineArg struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
@@ -52,7 +50,7 @@ func splitAfterSpace(inputChar rune) bool {
|
||||
}
|
||||
|
||||
// CmdlineArgs returns all the kernel cmdline. It is read from cat /proc/cmdline.
|
||||
func CmdlineArgs() ([]CmdlineArg, error) {
|
||||
func CmdlineArgs(cmdlineFilePath string) ([]CmdlineArg, error) {
|
||||
lines, err := ReadFileIntoLines(cmdlineFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading the file %s, %v", cmdlineFilePath, err)
|
||||
|
||||
@@ -69,15 +69,9 @@ func TestCmdlineStats(t *testing.T) {
|
||||
}
|
||||
for _, test := range testcases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
originalCmdlineFilePath := cmdlineFilePath
|
||||
defer func() {
|
||||
cmdlineFilePath = originalCmdlineFilePath
|
||||
}()
|
||||
|
||||
cmdlineFilePath = test.fakeCmdlineFilePath
|
||||
cmdlineArgs, err := CmdlineArgs()
|
||||
cmdlineArgs, err := CmdlineArgs(test.fakeCmdlineFilePath)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error retrieving cmdlineArgs: %v\nCmdlineArgsFilePath: %s\n", err, cmdlineFilePath)
|
||||
t.Errorf("Unexpected error retrieving cmdlineArgs: %v\nCmdlineArgsFilePath: %s\n", err, test.fakeCmdlineFilePath)
|
||||
}
|
||||
for _, expectedCmdlineArg := range test.expectedCmdlineArgs {
|
||||
assert.Contains(t, cmdlineArgs, expectedCmdlineArg, "Failed to find cmdlineArgs: %v\n", expectedCmdlineArg)
|
||||
|
||||
@@ -20,8 +20,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var modulesFilePath = "/proc/modules"
|
||||
|
||||
type Module struct {
|
||||
ModuleName string `json:"moduleName"`
|
||||
Instances uint64 `json:"instances"`
|
||||
@@ -37,7 +35,7 @@ func (d Module) String() string {
|
||||
|
||||
// Module returns all the kernel modules and their
|
||||
// usage. It is read from cat /proc/modules.
|
||||
func Modules() ([]Module, error) {
|
||||
func Modules(modulesFilePath string) ([]Module, error) {
|
||||
lines, err := ReadFileIntoLines(modulesFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading the contents of %s: %s", modulesFilePath, err)
|
||||
|
||||
@@ -97,15 +97,9 @@ func TestModules(t *testing.T) {
|
||||
}
|
||||
for _, test := range testcases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
originalModuleFilePath := modulesFilePath
|
||||
defer func() {
|
||||
modulesFilePath = originalModuleFilePath
|
||||
}()
|
||||
|
||||
modulesFilePath = test.fakeModuleFilePath
|
||||
modules, err := Modules()
|
||||
modules, err := Modules(test.fakeModuleFilePath)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error retrieving modules: %v\nModulesFilePath: %s\n", err, modulesFilePath)
|
||||
t.Errorf("Unexpected error retrieving modules: %v\nModulesFilePath: %s\n", err, test.fakeModuleFilePath)
|
||||
}
|
||||
assert.Equal(t, modules, test.expectedModules, "unpected modules retrieved: %v, expected: %v", modules, test.expectedModules)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user