diff options
Diffstat (limited to '')
-rw-r--r-- | src/go/collectors/go.d.plugin/modules/upsd/collect.go | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/upsd/collect.go b/src/go/collectors/go.d.plugin/modules/upsd/collect.go new file mode 100644 index 000000000..39e3d1b55 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/upsd/collect.go @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package upsd + +import ( + "errors" + "strconv" + "strings" +) + +func (u *Upsd) collect() (map[string]int64, error) { + if u.conn == nil { + conn, err := u.establishConnection() + if err != nil { + return nil, err + } + u.conn = conn + } + + upsUnits, err := u.conn.upsUnits() + if err != nil { + if !errors.Is(err, errUpsdCommand) { + _ = u.conn.disconnect() + u.conn = nil + } + return nil, err + } + + u.Debugf("found %d UPS units", len(upsUnits)) + + mx := make(map[string]int64) + + u.collectUPSUnits(mx, upsUnits) + + return mx, nil +} + +func (u *Upsd) establishConnection() (upsdConn, error) { + conn := u.newUpsdConn(u.Config) + + if err := conn.connect(); err != nil { + return nil, err + } + + if u.Username != "" && u.Password != "" { + if err := conn.authenticate(u.Username, u.Password); err != nil { + _ = conn.disconnect() + return nil, err + } + } + + return conn, nil +} + +func (u *Upsd) collectUPSUnits(mx map[string]int64, upsUnits []upsUnit) { + seen := make(map[string]bool) + + for _, ups := range upsUnits { + seen[ups.name] = true + u.Debugf("collecting metrics UPS '%s'", ups.name) + + if !u.upsUnits[ups.name] { + u.upsUnits[ups.name] = true + u.addUPSCharts(ups) + } + + writeVar(mx, ups, varBatteryCharge) + writeVar(mx, ups, varBatteryRuntime) + writeVar(mx, ups, varBatteryVoltage) + writeVar(mx, ups, varBatteryVoltageNominal) + + writeVar(mx, ups, varInputVoltage) + writeVar(mx, ups, varInputVoltageNominal) + writeVar(mx, ups, varInputCurrent) + writeVar(mx, ups, varInputCurrentNominal) + writeVar(mx, ups, varInputFrequency) + writeVar(mx, ups, varInputFrequencyNominal) + + writeVar(mx, ups, varOutputVoltage) + writeVar(mx, ups, varOutputVoltageNominal) + writeVar(mx, ups, varOutputCurrent) + writeVar(mx, ups, varOutputCurrentNominal) + writeVar(mx, ups, varOutputFrequency) + writeVar(mx, ups, varOutputFrequencyNominal) + + writeVar(mx, ups, varUpsLoad) + writeVar(mx, ups, varUpsRealPowerNominal) + writeVar(mx, ups, varUpsTemperature) + writeUpsLoadUsage(mx, ups) + writeUpsStatus(mx, ups) + } + + for name := range u.upsUnits { + if !seen[name] { + delete(u.upsUnits, name) + u.removeUPSCharts(name) + } + } +} + +func writeVar(mx map[string]int64, ups upsUnit, v string) { + s, ok := ups.vars[v] + if !ok { + return + } + n, err := strconv.ParseFloat(s, 64) + if err != nil { + return + } + mx[prefix(ups)+v] = int64(n * varPrecision) +} + +func writeUpsLoadUsage(mx map[string]int64, ups upsUnit) { + if hasVar(ups.vars, varUpsRealPower) { + pow, _ := strconv.ParseFloat(ups.vars[varUpsRealPower], 64) + mx[prefix(ups)+"ups.load.usage"] = int64(pow * varPrecision) + return + } + + if !hasVar(ups.vars, varUpsLoad) || !hasVar(ups.vars, varUpsRealPowerNominal) { + return + } + load, err := strconv.ParseFloat(ups.vars[varUpsLoad], 64) + if err != nil { + return + } + nomPower, err := strconv.ParseFloat(ups.vars[varUpsRealPowerNominal], 64) + if err != nil || nomPower == 0 { + return + } + mx[prefix(ups)+"ups.load.usage"] = int64((load / 100 * nomPower) * varPrecision) +} + +// https://networkupstools.org/docs/developer-guide.chunked/ar01s04.html#_status_data +var upsStatuses = map[string]bool{ + "OL": true, + "OB": true, + "LB": true, + "HB": true, + "RB": true, + "CHRG": true, + "DISCHRG": true, + "BYPASS": true, + "CAL": true, + "OFF": true, + "OVER": true, + "TRIM": true, + "BOOST": true, + "FSD": true, +} + +func writeUpsStatus(mx map[string]int64, ups upsUnit) { + if !hasVar(ups.vars, varUpsStatus) { + return + } + + px := prefix(ups) + "ups.status." + + for st := range upsStatuses { + mx[px+st] = 0 + } + mx[px+"other"] = 0 + + for _, st := range strings.Split(ups.vars[varUpsStatus], " ") { + if _, ok := upsStatuses[st]; ok { + mx[px+st] = 1 + } else { + mx[px+"other"] = 1 + } + } +} + +func hasVar(vars map[string]string, v string) bool { + _, ok := vars[v] + return ok +} + +func prefix(ups upsUnit) string { + return "ups_" + ups.name + "_" +} |