Add cmdstat metrics to redis input (#5926)

This commit is contained in:
Adam Flott 2019-08-16 18:46:48 -04:00 committed by Daniel Nelson
parent 50dc8d5659
commit 96fa7fa6d2
3 changed files with 86 additions and 1 deletions

View File

@ -120,6 +120,13 @@ Additionally the plugin also calculates the hit/miss ratio (keyspace\_hitrate) a
- expires(int, number)
- avg_ttl(int, number)
- redis_cmdstat
Every Redis used command will have 3 new fields:
- calls(int, number)
- usec(int, mircoseconds)
- usec_per_call(float, microseconds)
### Tags:
- All measurements have the following tags:
@ -130,6 +137,9 @@ Additionally the plugin also calculates the hit/miss ratio (keyspace\_hitrate) a
- The redis_keyspace measurement has an additional database tag:
- database
- The redis_cmdstat measurement has an additional tag:
- command
### Example Output:
Using this configuration:
@ -161,3 +171,8 @@ redis_keyspace:
```
> redis_keyspace,database=db1,host=host,server=localhost,port=6379,replication_role=master keys=1i,expires=0i,avg_ttl=0i 1493101350000000000
```
redis_command:
```
> redis_cmdstat,command=publish,host=host,port=6379,replication_role=master,server=localhost calls=68113i,usec=325146i,usec_per_call=4.77 1559227136000000000
```

View File

@ -37,7 +37,7 @@ type RedisClient struct {
}
func (r *RedisClient) Info() *redis.StringCmd {
return r.client.Info()
return r.client.Info("ALL")
}
func (r *RedisClient) BaseTags() map[string]string {
@ -248,6 +248,11 @@ func gatherInfoOutput(
gatherKeyspaceLine(name, kline, acc, tags)
continue
}
if section == "Commandstats" {
kline := strings.TrimSpace(parts[1])
gatherCommandstateLine(name, kline, acc, tags)
continue
}
metric = name
}
@ -324,6 +329,51 @@ func gatherKeyspaceLine(
}
}
// Parse the special cmdstat lines.
// Example:
// cmdstat_publish:calls=33791,usec=208789,usec_per_call=6.18
// Tag: cmdstat=publish; Fields: calls=33791i,usec=208789i,usec_per_call=6.18
func gatherCommandstateLine(
name string,
line string,
acc telegraf.Accumulator,
global_tags map[string]string,
) {
if !strings.HasPrefix(name, "cmdstat") {
return
}
fields := make(map[string]interface{})
tags := make(map[string]string)
for k, v := range global_tags {
tags[k] = v
}
tags["command"] = strings.TrimPrefix(name, "cmdstat_")
parts := strings.Split(line, ",")
for _, part := range parts {
kv := strings.Split(part, "=")
if len(kv) != 2 {
continue
}
switch kv[0] {
case "calls":
fallthrough
case "usec":
ival, err := strconv.ParseInt(kv[1], 10, 64)
if err == nil {
fields[kv[0]] = ival
}
case "usec_per_call":
fval, err := strconv.ParseFloat(kv[1], 64)
if err == nil {
fields[kv[0]] = fval
}
}
}
acc.AddFields("redis_cmdstat", fields, tags)
}
func init() {
inputs.Add("redis", func() telegraf.Input {
return &Redis{}

View File

@ -118,6 +118,22 @@ func TestRedis_ParseMetrics(t *testing.T) {
}
acc.AssertContainsTaggedFields(t, "redis", fields, tags)
acc.AssertContainsTaggedFields(t, "redis_keyspace", keyspaceFields, keyspaceTags)
cmdstatSetTags := map[string]string{"host": "redis.net", "replication_role": "master", "command": "set"}
cmdstatSetFields := map[string]interface{}{
"calls": int64(261265),
"usec": int64(1634157),
"usec_per_call": float64(6.25),
}
acc.AssertContainsTaggedFields(t, "redis_cmdstat", cmdstatSetFields, cmdstatSetTags)
cmdstatCommandTags := map[string]string{"host": "redis.net", "replication_role": "master", "command": "command"}
cmdstatCommandFields := map[string]interface{}{
"calls": int64(1),
"usec": int64(990),
"usec_per_call": float64(990.0),
}
acc.AssertContainsTaggedFields(t, "redis_cmdstat", cmdstatCommandFields, cmdstatCommandTags)
}
const testOutput = `# Server
@ -209,6 +225,10 @@ used_cpu_user:0.05
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
# Commandstats
cmdstat_set:calls=261265,usec=1634157,usec_per_call=6.25
cmdstat_command:calls=1,usec=990,usec_per_call=990.00
# Keyspace
db0:keys=2,expires=0,avg_ttl=0