218 lines
5.2 KiB
Go
218 lines
5.2 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"math"
|
||
|
"strconv"
|
||
|
|
||
|
"github.com/prometheus/client_golang/prometheus"
|
||
|
"github.com/prometheus/common/log"
|
||
|
|
||
|
"github.com/soundcloud/ipmi_exporter/freeipmi"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
IPMICollectorName CollectorName = "ipmi"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
sensorStateDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "sensor", "state"),
|
||
|
"Indicates the severity of the state reported by an IPMI sensor (0=nominal, 1=warning, 2=critical).",
|
||
|
[]string{"id", "name", "type"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
sensorValueDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "sensor", "value"),
|
||
|
"Generic data read from an IPMI sensor of unknown type, relying on labels for context.",
|
||
|
[]string{"id", "name", "type"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
fanSpeedDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "fan_speed", "rpm"),
|
||
|
"Fan speed in rotations per minute.",
|
||
|
[]string{"id", "name"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
fanSpeedStateDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "fan_speed", "state"),
|
||
|
"Reported state of a fan speed sensor (0=nominal, 1=warning, 2=critical).",
|
||
|
[]string{"id", "name"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
temperatureDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "temperature", "celsius"),
|
||
|
"Temperature reading in degree Celsius.",
|
||
|
[]string{"id", "name"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
temperatureStateDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "temperature", "state"),
|
||
|
"Reported state of a temperature sensor (0=nominal, 1=warning, 2=critical).",
|
||
|
[]string{"id", "name"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
voltageDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "voltage", "volts"),
|
||
|
"Voltage reading in Volts.",
|
||
|
[]string{"id", "name"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
voltageStateDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "voltage", "state"),
|
||
|
"Reported state of a voltage sensor (0=nominal, 1=warning, 2=critical).",
|
||
|
[]string{"id", "name"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
currentDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "current", "amperes"),
|
||
|
"Current reading in Amperes.",
|
||
|
[]string{"id", "name"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
currentStateDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "current", "state"),
|
||
|
"Reported state of a current sensor (0=nominal, 1=warning, 2=critical).",
|
||
|
[]string{"id", "name"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
powerDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "power", "watts"),
|
||
|
"Power reading in Watts.",
|
||
|
[]string{"id", "name"},
|
||
|
nil,
|
||
|
)
|
||
|
|
||
|
powerStateDesc = prometheus.NewDesc(
|
||
|
prometheus.BuildFQName(namespace, "power", "state"),
|
||
|
"Reported state of a power sensor (0=nominal, 1=warning, 2=critical).",
|
||
|
[]string{"id", "name"},
|
||
|
nil,
|
||
|
)
|
||
|
)
|
||
|
|
||
|
type IPMICollector struct{}
|
||
|
|
||
|
func (c IPMICollector) Name() CollectorName {
|
||
|
return IPMICollectorName
|
||
|
}
|
||
|
|
||
|
func (c IPMICollector) Cmd() string {
|
||
|
return "ipmimonitoring"
|
||
|
}
|
||
|
|
||
|
func (c IPMICollector) Args() []string {
|
||
|
return []string{
|
||
|
"-Q",
|
||
|
"--ignore-unrecognized-events",
|
||
|
"--comma-separated-output",
|
||
|
"--no-header-output",
|
||
|
"--sdr-cache-recreate",
|
||
|
"--output-event-bitmask",
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c IPMICollector) Collect(result freeipmi.Result, ch chan<- prometheus.Metric, target ipmiTarget) (int, error) {
|
||
|
excludeIds := target.config.ExcludeSensorIDs
|
||
|
results, err := freeipmi.GetSensorData(result, excludeIds)
|
||
|
if err != nil {
|
||
|
log.Errorf("Failed to collect sensor data from %s: %s", targetName(target.host), err)
|
||
|
return 0, err
|
||
|
}
|
||
|
for _, data := range results {
|
||
|
var state float64
|
||
|
|
||
|
switch data.State {
|
||
|
case "Nominal":
|
||
|
state = 0
|
||
|
case "Warning":
|
||
|
state = 1
|
||
|
case "Critical":
|
||
|
state = 2
|
||
|
case "N/A":
|
||
|
state = math.NaN()
|
||
|
default:
|
||
|
log.Errorf("Unknown sensor state: '%s'\n", data.State)
|
||
|
state = math.NaN()
|
||
|
}
|
||
|
|
||
|
log.Debugf("Got values: %v\n", data)
|
||
|
|
||
|
switch data.Unit {
|
||
|
case "RPM":
|
||
|
collectTypedSensor(ch, fanSpeedDesc, fanSpeedStateDesc, state, data)
|
||
|
case "C":
|
||
|
collectTypedSensor(ch, temperatureDesc, temperatureStateDesc, state, data)
|
||
|
case "A":
|
||
|
collectTypedSensor(ch, currentDesc, currentStateDesc, state, data)
|
||
|
case "V":
|
||
|
collectTypedSensor(ch, voltageDesc, voltageStateDesc, state, data)
|
||
|
case "W":
|
||
|
collectTypedSensor(ch, powerDesc, powerStateDesc, state, data)
|
||
|
default:
|
||
|
collectGenericSensor(ch, state, data)
|
||
|
}
|
||
|
}
|
||
|
return 1, nil
|
||
|
}
|
||
|
|
||
|
func (c IPMICollector) Describe(ch chan<- *prometheus.Desc) {
|
||
|
ch <- sensorStateDesc
|
||
|
ch <- sensorValueDesc
|
||
|
ch <- fanSpeedDesc
|
||
|
ch <- fanSpeedStateDesc
|
||
|
ch <- temperatureDesc
|
||
|
ch <- temperatureStateDesc
|
||
|
ch <- voltageDesc
|
||
|
ch <- voltageStateDesc
|
||
|
ch <- currentDesc
|
||
|
ch <- currentStateDesc
|
||
|
ch <- powerDesc
|
||
|
ch <- powerStateDesc
|
||
|
}
|
||
|
|
||
|
func collectTypedSensor(ch chan<- prometheus.Metric, desc, stateDesc *prometheus.Desc, state float64, data freeipmi.SensorData) {
|
||
|
ch <- prometheus.MustNewConstMetric(
|
||
|
desc,
|
||
|
prometheus.GaugeValue,
|
||
|
data.Value,
|
||
|
strconv.FormatInt(data.ID, 10),
|
||
|
data.Name,
|
||
|
)
|
||
|
ch <- prometheus.MustNewConstMetric(
|
||
|
stateDesc,
|
||
|
prometheus.GaugeValue,
|
||
|
state,
|
||
|
strconv.FormatInt(data.ID, 10),
|
||
|
data.Name,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func collectGenericSensor(ch chan<- prometheus.Metric, state float64, data freeipmi.SensorData) {
|
||
|
ch <- prometheus.MustNewConstMetric(
|
||
|
sensorValueDesc,
|
||
|
prometheus.GaugeValue,
|
||
|
data.Value,
|
||
|
strconv.FormatInt(data.ID, 10),
|
||
|
data.Name,
|
||
|
data.Type,
|
||
|
)
|
||
|
ch <- prometheus.MustNewConstMetric(
|
||
|
sensorStateDesc,
|
||
|
prometheus.GaugeValue,
|
||
|
state,
|
||
|
strconv.FormatInt(data.ID, 10),
|
||
|
data.Name,
|
||
|
data.Type,
|
||
|
)
|
||
|
}
|