Add collector to read data from ipmitool or ipmi-sensors (fallback) (#9)

* Add collector to read data from ipmitool or ipmi-sensors

* Update IPMI collector to use own config

* Add 'ipmitool sensor' parser
This commit is contained in:
Thomas Gruber 2021-11-25 18:15:56 +01:00 committed by GitHub
parent c6edf7aed4
commit 1e7a75598e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 139 additions and 0 deletions

View File

@ -40,6 +40,7 @@ The base class/configuration is located in `metricCollector.go`.
* `cpustatMetric.go`: Read CPU specific values from `/proc/stat` * `cpustatMetric.go`: Read CPU specific values from `/proc/stat`
* `topprocsMetric.go`: Reads the Top5 processes by their CPU usage * `topprocsMetric.go`: Reads the Top5 processes by their CPU usage
* `nvidiaMetric.go`: Read data about Nvidia GPUs using the NVML library * `nvidiaMetric.go`: Read data about Nvidia GPUs using the NVML library
* `ipmiMetric.go`: Collect data from `ipmitool` or as fallback `ipmi-sensors`
If any of the collectors cannot be initialized, it is excluded from all further reads. Like if the Lustre stat file is not a valid path, no Lustre specific metrics will be recorded. If any of the collectors cannot be initialized, it is excluded from all further reads. Like if the Lustre stat file is not a valid path, no Lustre specific metrics will be recorded.

137
collectors/ipmiMetric.go Normal file
View File

@ -0,0 +1,137 @@
package collectors
import (
"errors"
lp "github.com/influxdata/line-protocol"
"log"
"strconv"
"strings"
"time"
"os"
"os/exec"
"encoding/json"
)
const IPMITOOL_PATH = `/usr/bin/ipmitool`
const IPMISENSORS_PATH = `/usr/sbin/ipmi-sensors`
type IpmiCollectorConfig struct {
ExcludeDevices []string `json:"exclude_devices"`
IpmitoolPath string `json:"ipmitool_path"`
IpmisensorsPath string `json:"ipmisensors_path"`
}
type IpmiCollector struct {
MetricCollector
tags map[string]string
matches map[string]string
config IpmiCollectorConfig
}
func (m *IpmiCollector) Init(config []byte) error {
m.name = "IpmiCollector"
m.setup()
if len(config) > 0 {
err := json.Unmarshal(config, &m.config)
if err != nil {
return err
}
}
_, err1 := os.Stat(m.config.IpmitoolPath)
_, err2 := os.Stat(m.config.IpmisensorsPath)
if err1 != nil {
m.config.IpmitoolPath = ""
}
if err2 != nil {
m.config.IpmisensorsPath = ""
}
if err1 != nil && err2 != nil {
return errors.New("No IPMI reader found")
}
m.init = true
return nil
}
func ReadIpmiTool(cmd string, out *[]lp.MutableMetric) {
command := exec.Command(cmd, "sensor")
command.Wait()
stdout, err := command.Output()
if err != nil {
log.Print(err)
return
}
ll := strings.Split(string(stdout), "\n")
for _, line := range ll {
lv := strings.Split(line, "|")
if len(lv) < 3 {
continue
}
v, err := strconv.ParseFloat(strings.Trim(lv[1], " "), 64)
if err == nil {
name := strings.ToLower(strings.Replace(strings.Trim(lv[0], " "), " ", "_", -1))
unit := strings.Trim(lv[2], " ")
if unit == "Volts" {
unit = "V"
} else if unit == "degrees C" {
unit = "C"
} else if unit == "degrees F" {
unit = "F"
} else if unit == "Watts" {
unit = "W"
}
y, err := lp.New(name, map[string]string{"unit": unit, "type" : "node"}, map[string]interface{}{"value": v}, time.Now())
if err == nil {
*out = append(*out, y)
}
}
}
}
func ReadIpmiSensors(cmd string, out *[]lp.MutableMetric) {
command := exec.Command(cmd, "--comma-separated-output", "--sdr-cache-recreate")
command.Wait()
stdout, err := command.Output()
if err != nil {
log.Print(err)
return
}
ll := strings.Split(string(stdout), "\n")
for _, line := range ll {
lv := strings.Split(line, ",")
if len(lv) > 3 {
v, err := strconv.ParseFloat(lv[3], 64)
if err == nil {
name := strings.ToLower(strings.Replace(lv[1], " ", "_", -1))
y, err := lp.New(name, map[string]string{"unit": lv[4], "type" : "node"}, map[string]interface{}{"value": v}, time.Now())
if err == nil {
*out = append(*out, y)
}
}
}
}
}
func (m *IpmiCollector) Read(interval time.Duration, out *[]lp.MutableMetric) {
if len(m.config.IpmitoolPath) > 0 {
_, err := os.Stat(m.config.IpmitoolPath)
if err == nil {
ReadIpmiTool(m.config.IpmitoolPath, out)
}
} else if len(m.config.IpmisensorsPath) > 0 {
_, err := os.Stat(m.config.IpmisensorsPath)
if err == nil {
ReadIpmiSensors(m.config.IpmisensorsPath, out)
}
}
}
func (m *IpmiCollector) Close() {
m.init = false
return
}

View File

@ -30,6 +30,7 @@ var Collectors = map[string]collectors.MetricGetter{
"nvidia": &collectors.NvidiaCollector{}, "nvidia": &collectors.NvidiaCollector{},
"customcmd": &collectors.CustomCmdCollector{}, "customcmd": &collectors.CustomCmdCollector{},
"diskstat": &collectors.DiskstatCollector{}, "diskstat": &collectors.DiskstatCollector{},
"ipmistat" : &collectors.IpmiCollector{},
} }
var Sinks = map[string]sinks.SinkFuncs{ var Sinks = map[string]sinks.SinkFuncs{