fix(inputs.zookeeper): add the ability to parse floats as floats (#12023)

This commit is contained in:
Joshua Powers 2022-10-19 10:15:32 -06:00 committed by GitHub
parent c5e2c7aa00
commit 13a020f491
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 33 deletions

View File

@ -24,6 +24,12 @@ specific to using `mntr` to collect the Java Properties format.
## Timeout for metric collections from all servers. Minimum timeout is "1s". ## Timeout for metric collections from all servers. Minimum timeout is "1s".
# timeout = "5s" # timeout = "5s"
## Float Parsing - the initial implementation forced any value unable to be
## parsed as an int to be a string. Setting this to "float" will attempt to
## parse float values as floats and not strings. This would break existing
## metrics and may cause issues if a value switches between a float and int.
# parse_floats = "string"
## Optional TLS Config ## Optional TLS Config
# enable_tls = false # enable_tls = false
# tls_ca = "/etc/telegraf/ca.pem" # tls_ca = "/etc/telegraf/ca.pem"

View File

@ -10,6 +10,12 @@
## Timeout for metric collections from all servers. Minimum timeout is "1s". ## Timeout for metric collections from all servers. Minimum timeout is "1s".
# timeout = "5s" # timeout = "5s"
## Float Parsing - the initial implementation forced any value unable to be
## parsed as an int to be a string. Setting this to "float" will attempt to
## parse float values as floats and not strings. This would break existing
## metrics and may cause issues if a value switches between a float and int.
# parse_floats = "string"
## Optional TLS Config ## Optional TLS Config
# enable_tls = false # enable_tls = false
# tls_ca = "/etc/telegraf/ca.pem" # tls_ca = "/etc/telegraf/ca.pem"

View File

@ -26,8 +26,9 @@ var zookeeperFormatRE = regexp.MustCompile(`^zk_(\w[\w\.\-]*)\s+([\w\.\-]+)`)
// Zookeeper is a zookeeper plugin // Zookeeper is a zookeeper plugin
type Zookeeper struct { type Zookeeper struct {
Servers []string Servers []string `toml:"servers"`
Timeout config.Duration Timeout config.Duration `toml:"timeout"`
ParseFloats string `toml:"parse_floats"`
EnableTLS bool `toml:"enable_tls"` EnableTLS bool `toml:"enable_tls"`
EnableSSL bool `toml:"enable_ssl" deprecated:"1.7.0;use 'enable_tls' instead"` EnableSSL bool `toml:"enable_ssl" deprecated:"1.7.0;use 'enable_tls' instead"`
@ -129,16 +130,29 @@ func (z *Zookeeper) gatherServer(ctx context.Context, address string, acc telegr
measurement := strings.TrimPrefix(parts[1], "zk_") measurement := strings.TrimPrefix(parts[1], "zk_")
if measurement == "server_state" { if measurement == "server_state" {
zookeeperState = parts[2] zookeeperState = parts[2]
} else { continue
sValue := parts[2] }
iVal, err := strconv.ParseInt(sValue, 10, 64) sValue := parts[2]
// First attempt to parse as an int
iVal, err := strconv.ParseInt(sValue, 10, 64)
if err == nil {
fields[measurement] = iVal
continue
}
// If set, attempt to parse as a float
if z.ParseFloats == "float" {
fVal, err := strconv.ParseFloat(sValue, 64)
if err == nil { if err == nil {
fields[measurement] = iVal fields[measurement] = fVal
} else { continue
fields[measurement] = sValue
} }
} }
// Finally, save as a string
fields[measurement] = sValue
} }
srv := "localhost" srv := "localhost"

View File

@ -34,35 +34,56 @@ func TestZookeeperGeneratesMetricsIntegration(t *testing.T) {
require.NoError(t, container.Terminate(), "terminating container failed") require.NoError(t, container.Terminate(), "terminating container failed")
}() }()
z := &Zookeeper{ var testset = []struct {
Servers: []string{ name string
fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort]), zookeeper Zookeeper
}{
{
name: "floats as strings",
zookeeper: Zookeeper{
Servers: []string{
fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort]),
},
},
},
{
name: "floats as floats",
zookeeper: Zookeeper{
Servers: []string{
fmt.Sprintf("%s:%s", container.Address, container.Ports[servicePort]),
},
ParseFloats: "float",
},
}, },
} }
for _, tt := range testset {
t.Run(tt.name, func(t *testing.T) {
var acc testutil.Accumulator
require.NoError(t, acc.GatherError(tt.zookeeper.Gather))
var acc testutil.Accumulator intMetrics := []string{
"max_latency",
"min_latency",
"packets_received",
"packets_sent",
"outstanding_requests",
"znode_count",
"watch_count",
"ephemerals_count",
"approximate_data_size",
"open_file_descriptor_count",
"max_file_descriptor_count",
}
require.NoError(t, acc.GatherError(z.Gather)) for _, metric := range intMetrics {
require.True(t, acc.HasInt64Field("zookeeper", metric), metric)
}
intMetrics := []string{ if tt.zookeeper.ParseFloats == "float" {
"max_latency", require.True(t, acc.HasFloatField("zookeeper", "avg_latency"), "avg_latency not a float")
"min_latency", } else {
"packets_received", require.True(t, acc.HasStringField("zookeeper", "avg_latency"), "avg_latency not a string")
"packets_sent", }
"outstanding_requests", })
"znode_count",
"watch_count",
"ephemerals_count",
"approximate_data_size",
"open_file_descriptor_count",
"max_file_descriptor_count",
} }
for _, metric := range intMetrics {
require.True(t, acc.HasInt64Field("zookeeper", metric), metric)
}
// Currently we output floats as strings (see #8863), but the desired behavior is to have floats
require.True(t, acc.HasStringField("zookeeper", "avg_latency"), "avg_latency")
// require.True(t, acc.HasFloat64Field("zookeeper", "avg_latency"), "avg_latency")
} }