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
# username = "user"
# 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

View File

@ -5,3 +5,9 @@
# port = 3493
# username = "user"
# 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,10 +22,12 @@ const defaultAddress = "127.0.0.1"
const defaultPort = 3493
type Upsd struct {
Server string
Port int
Username string
Password string
Server string `toml:"server"`
Port int `toml:"port"`
Username string `toml:"username"`
Password string `toml:"password"`
ForceFloat bool `toml:"force_float"`
Log telegraf.Logger `toml:"-"`
batteryRuntimeTypeWarningIssued bool
@ -71,27 +73,51 @@ func (u *Upsd) gatherUps(acc telegraf.Accumulator, name string, variables []nut.
}
fields := map[string]interface{}{
"status_flags": status,
"ups_status": metrics["ups.status"],
"input_voltage": metrics["input.voltage"],
"load_percent": metrics["ups.load"],
"battery_charge_percent": metrics["battery.charge"],
"time_left_ns": timeLeftS * 1_000_000_000, //Compatibility with apcupsd metrics format
"output_voltage": metrics["output.voltage"],
"internal_temp": metrics["ups.temperature"],
"battery_voltage": metrics["battery.voltage"],
"input_frequency": metrics["input.frequency"],
"nominal_input_voltage": metrics["input.voltage.nominal"],
"nominal_battery_voltage": metrics["battery.voltage.nominal"],
"nominal_power": metrics["ups.realpower.nominal"],
"battery_date": metrics["battery.mfr.date"],
"status_flags": status,
//Compatibility with apcupsd metrics format
"time_left_ns": timeLeftS * 1_000_000_000,
"ups_status": metrics["ups.status"],
}
floatValues := map[string]string{
"battery_charge_percent": "battery.charge",
"battery_voltage": "battery.voltage",
"input_frequency": "input.frequency",
"input_voltage": "input.voltage",
"internal_temp": "ups.temperature",
"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"])
if err != nil {
acc.AddError(fmt.Errorf("converting ups.firmware=%v failed: %v", metrics["ups.firmware"], err))
}
} else {
fields["firmware"] = val
}
acc.AddFields("upsd", fields, tags)
}

View File

@ -16,6 +16,7 @@ func TestUpsdGather(t *testing.T) {
var (
tests = []struct {
name string
forceFloat bool
err bool
tags map[string]string
fields map[string]interface{}
@ -23,6 +24,34 @@ func TestUpsdGather(t *testing.T) {
}{
{
name: "test listening server with output",
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{
"serial": "ABC123",
@ -35,9 +64,7 @@ func TestUpsdGather(t *testing.T) {
"ups_status": "OL",
"battery_charge_percent": float64(100),
"battery_voltage": float64(13.4),
"input_frequency": nil,
"input_voltage": float64(242),
"internal_temp": nil,
"load_percent": float64(23),
"output_voltage": float64(230),
"time_left_ns": int64(600000000000),
@ -63,6 +90,7 @@ func TestUpsdGather(t *testing.T) {
nut.Server = (lAddr.(*net.TCPAddr)).IP.String()
nut.Port = (lAddr.(*net.TCPAddr)).Port
nut.ForceFloat = tt.forceFloat
err = nut.Gather(&acc)
if tt.err {