fix(inputs.upsd): Always convert to float (#12516)

This commit is contained in:
Joshua Powers 2023-01-26 02:57:23 -07:00 committed by GitHub
parent a8745886e9
commit 4b445f6a26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 95 additions and 29 deletions

View File

@ -26,6 +26,12 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
# port = 3493 # port = 3493
# username = "user" # username = "user"
# password = "password" # password = "password"
## Force parsing numbers as floats
## It is highly recommended to enable this setting to parse numbers
## consistently as floats to avoid database conflicts where some numbers are
## parsed as integers and others as floats.
# force_float = false
``` ```
## Metrics ## Metrics

View File

@ -5,3 +5,9 @@
# port = 3493 # port = 3493
# username = "user" # username = "user"
# password = "password" # password = "password"
## Force parsing numbers as floats
## It is highly recommended to enable this setting to parse numbers
## consistently as floats to avoid database conflicts where some numbers are
## parsed as integers and others as floats.
# force_float = false

View File

@ -22,11 +22,13 @@ const defaultAddress = "127.0.0.1"
const defaultPort = 3493 const defaultPort = 3493
type Upsd struct { type Upsd struct {
Server string Server string `toml:"server"`
Port int Port int `toml:"port"`
Username string Username string `toml:"username"`
Password string Password string `toml:"password"`
Log telegraf.Logger `toml:"-"` ForceFloat bool `toml:"force_float"`
Log telegraf.Logger `toml:"-"`
batteryRuntimeTypeWarningIssued bool batteryRuntimeTypeWarningIssued bool
} }
@ -71,27 +73,51 @@ func (u *Upsd) gatherUps(acc telegraf.Accumulator, name string, variables []nut.
} }
fields := map[string]interface{}{ fields := map[string]interface{}{
"status_flags": status, "battery_date": metrics["battery.mfr.date"],
"ups_status": metrics["ups.status"], "status_flags": status,
"input_voltage": metrics["input.voltage"], //Compatibility with apcupsd metrics format
"load_percent": metrics["ups.load"], "time_left_ns": timeLeftS * 1_000_000_000,
"battery_charge_percent": metrics["battery.charge"], "ups_status": metrics["ups.status"],
"time_left_ns": timeLeftS * 1_000_000_000, //Compatibility with apcupsd metrics format }
"output_voltage": metrics["output.voltage"],
"internal_temp": metrics["ups.temperature"], floatValues := map[string]string{
"battery_voltage": metrics["battery.voltage"], "battery_charge_percent": "battery.charge",
"input_frequency": metrics["input.frequency"], "battery_voltage": "battery.voltage",
"nominal_input_voltage": metrics["input.voltage.nominal"], "input_frequency": "input.frequency",
"nominal_battery_voltage": metrics["battery.voltage.nominal"], "input_voltage": "input.voltage",
"nominal_power": metrics["ups.realpower.nominal"], "internal_temp": "ups.temperature",
"battery_date": metrics["battery.mfr.date"], "load_percent": "ups.load",
"nominal_battery_voltage": "battery.voltage.nominal",
"nominal_input_voltage": "input.voltage.nominal",
"nominal_power": "ups.realpower.nominal",
"output_voltage": "output.voltage",
}
for key, rawValue := range floatValues {
if metrics[rawValue] == nil {
continue
}
if !u.ForceFloat {
fields[key] = metrics[rawValue]
continue
}
// Force expected float values to actually being float (e.g. if delivered as int)
float, err := internal.ToFloat64(metrics[rawValue])
if err != nil {
acc.AddError(fmt.Errorf("converting %s=%v failed: %v", rawValue, metrics[rawValue], err))
continue
}
fields[key] = float
} }
val, err := internal.ToString(metrics["ups.firmware"]) val, err := internal.ToString(metrics["ups.firmware"])
if err != nil { if err != nil {
acc.AddError(fmt.Errorf("converting ups.firmware=%v failed: %v", metrics["ups.firmware"], err)) acc.AddError(fmt.Errorf("converting ups.firmware=%v failed: %v", metrics["ups.firmware"], err))
} else {
fields["firmware"] = val
} }
fields["firmware"] = val
acc.AddFields("upsd", fields, tags) acc.AddFields("upsd", fields, tags)
} }

View File

@ -15,15 +15,44 @@ func TestUpsdGather(t *testing.T) {
var ( var (
tests = []struct { tests = []struct {
name string name string
err bool forceFloat bool
tags map[string]string err bool
fields map[string]interface{} tags map[string]string
out func() []interaction fields map[string]interface{}
out func() []interaction
}{ }{
{ {
name: "test listening server with output", name: "test listening server with output",
err: false, forceFloat: false,
err: false,
tags: map[string]string{
"serial": "ABC123",
"ups_name": "fake",
"model": "Model 12345",
"status_OL": "true",
},
fields: map[string]interface{}{
"status_flags": uint64(8),
"ups_status": "OL",
"battery_charge_percent": float64(100),
"battery_voltage": float64(13.4),
"input_voltage": float64(242),
"load_percent": float64(23),
"output_voltage": float64(230),
"time_left_ns": int64(600000000000),
"nominal_input_voltage": float64(230),
"nominal_battery_voltage": float64(24),
"nominal_power": int64(700),
"firmware": "CUSTOM_FIRMWARE",
"battery_date": "2016-07-26",
},
out: genOutput,
},
{
name: "test listening server with output & force floats",
forceFloat: true,
err: false,
tags: map[string]string{ tags: map[string]string{
"serial": "ABC123", "serial": "ABC123",
"ups_name": "fake", "ups_name": "fake",
@ -35,9 +64,7 @@ func TestUpsdGather(t *testing.T) {
"ups_status": "OL", "ups_status": "OL",
"battery_charge_percent": float64(100), "battery_charge_percent": float64(100),
"battery_voltage": float64(13.4), "battery_voltage": float64(13.4),
"input_frequency": nil,
"input_voltage": float64(242), "input_voltage": float64(242),
"internal_temp": nil,
"load_percent": float64(23), "load_percent": float64(23),
"output_voltage": float64(230), "output_voltage": float64(230),
"time_left_ns": int64(600000000000), "time_left_ns": int64(600000000000),
@ -63,6 +90,7 @@ func TestUpsdGather(t *testing.T) {
nut.Server = (lAddr.(*net.TCPAddr)).IP.String() nut.Server = (lAddr.(*net.TCPAddr)).IP.String()
nut.Port = (lAddr.(*net.TCPAddr)).Port nut.Port = (lAddr.(*net.TCPAddr)).Port
nut.ForceFloat = tt.forceFloat
err = nut.Gather(&acc) err = nut.Gather(&acc)
if tt.err { if tt.err {