Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Get each command stats from INFO all command on redis module #29662

Merged
merged 8 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 28 additions & 16 deletions metricbeat/module/redis/info/_meta/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,30 @@
"info": {
"clients": {
"blocked": 0,
"connected": 1,
"connected": 2,
"max_input_buffer": 0,
"max_output_buffer": 0
},
"cluster": {
"enabled": false
},
"commandstats": {
"info": {
"calls": 19,
"usec": 2058,
"usec_per_call": 108.32
},
"slowlog": {
"calls": 19,
"usec": 171,
"usec_per_call": 9
}
},
"cpu": {
"used": {
"sys": 0.23,
"sys": 198.04,
"sys_children": 0,
"user": 0.05,
"user": 26.7,
"user_children": 0
}
},
Expand All @@ -42,17 +54,17 @@
"rss": {}
},
"fragmentation": {
"ratio": 2.85
"ratio": 2.78
},
"max": {
"policy": "noeviction",
"value": 0
},
"used": {
"lua": 37888,
"peak": 822456,
"rss": 2347008,
"value": 822456
"peak": 843312,
"rss": 2338816,
"value": 842288
}
},
"persistence": {
Expand Down Expand Up @@ -95,7 +107,7 @@
"copy_on_write": {},
"last_save": {
"changes_since": 0,
"time": 1633422962
"time": 1639711601
}
}
},
Expand All @@ -122,21 +134,21 @@
"git_dirty": "0",
"git_sha1": "00000000",
"hz": 10,
"lru_clock": 6033096,
"lru_clock": 12363944,
"mode": "standalone",
"multiplexing_api": "epoll",
"run_id": "ddfd6edda7dcd357ac9f24ebfb0ef8b3ee771f8d",
"run_id": "a2b83e50ce54d2b3d5efe96035c25996e7a1ff07",
"tcp_port": 6379,
"uptime": 86
"uptime": 42295
},
"slowlog": {
"count": 0
},
"stats": {
"active_defrag": {},
"commands_processed": 2,
"commands_processed": 38,
"connections": {
"received": 82,
"received": 19678,
"rejected": 0
},
"instantaneous": {
Expand All @@ -156,10 +168,10 @@
"migrate_cached_sockets": 0,
"net": {
"input": {
"bytes": 80
"bytes": 954
},
"output": {
"bytes": 2111
"bytes": 42601
}
},
"pubsub": {
Expand All @@ -177,7 +189,7 @@
}
},
"service": {
"address": "localhost:53854",
"address": "localhost:65457",
"type": "redis",
"version": "3.2.12"
}
Expand Down
17 changes: 17 additions & 0 deletions metricbeat/module/redis/info/_meta/fields.yml
Original file line number Diff line number Diff line change
Expand Up @@ -552,3 +552,20 @@
description: >
Count of slow operations

- name: commandstats
type: group
description: >
Redis command statistics
fields:
- name: COMMANDNAME.calls
type: long
description: >
The number of calls that reached command execution (not rejected).
- name: COMMANDNAME.usec
type: long
description: >
The total CPU time consumed by these commands.
- name: COMMANDNAME.usec_per_call
type: float
description: >
The average CPU consumed per command execution.
20 changes: 20 additions & 0 deletions metricbeat/module/redis/info/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package info

import (
"strings"

"github.com/elastic/beats/v7/libbeat/common"
s "github.com/elastic/beats/v7/libbeat/common/schema"
c "github.com/elastic/beats/v7/libbeat/common/schema/mapstrstr"
Expand Down Expand Up @@ -234,15 +236,33 @@ var (
}
)

func buildCommandstatsSchema(key string, schema s.Schema) {
// Build schema for each command
command := strings.Split(key, "_")[1]
schema[command] = s.Object{
"calls": c.Int("cmdstat_" + command + "_calls"),
"usec": c.Int("cmdstat_" + command + "_usec"),
"usec_per_call": c.Float("cmdstat_" + command + "_usec_per_call"),
}
}

// Map data to MapStr
func eventMapping(r mb.ReporterV2, info map[string]string) {
// Full mapping from info
source := map[string]interface{}{}
commandstatsSchema := s.Schema{}
for key, val := range info {
source[key] = val
if strings.Contains(key, "_calls") {
buildCommandstatsSchema(key, commandstatsSchema)
}
}
data, _ := schema.Apply(source)

// Add commandstats info
commandstatsData, _ := commandstatsSchema.Apply(source)
data["commandstats"] = commandstatsData

rootFields := common.MapStr{}
if v, err := data.GetValue("server.version"); err == nil {
rootFields.Put("service.version", v)
Expand Down
4 changes: 2 additions & 2 deletions metricbeat/module/redis/info/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ func (m *MetricSet) Fetch(r mb.ReporterV2) error {
}
}()

// Fetch default INFO.
info, err := redis.FetchRedisInfo("default", conn)
// Fetch all INFO.
info, err := redis.FetchRedisInfo("all", conn)
if err != nil {
return errors.Wrap(err, "failed to fetch redis info")
}
Expand Down
2 changes: 1 addition & 1 deletion metricbeat/module/redis/info/info_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestFetch(t *testing.T) {
t.Logf("%s/%s event: %+v", ms.Module().Name(), ms.Name(), event)

// Check fields
assert.Equal(t, 9, len(event))
assert.Equal(t, 10, len(event))
server := event["server"].(common.MapStr)
assert.Equal(t, "standalone", server["mode"])
}
Expand Down
26 changes: 25 additions & 1 deletion metricbeat/module/redis/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,15 @@ func ParseRedisInfo(info string) map[string]string {
// Values are separated by :
parts := ParseRedisLine(value, ":")
if len(parts) == 2 {
values[parts[0]] = parts[1]
if strings.Contains(parts[0], "cmdstat_") {
cmdstats := ParseRedisCommandStats(parts[0], parts[1])
for k, v := range cmdstats {
key := parts[0] + "_" + k
values[key] = v
}
} else {
values[parts[0]] = parts[1]
}
}
}
return values
Expand All @@ -63,6 +71,22 @@ func ParseRedisLine(s string, delimiter string) []string {
return strings.Split(s, delimiter)
}

// ParseRedisCommandStats parses a map of stats returned by INFO COMMANDSTATS
func ParseRedisCommandStats(key string, s string) map[string]string {
// calls=XX,usec=XXX,usec_per_call=XXX
results := strings.Split(s, ",")

values := map[string]string{}

for _, value := range results {
parts := strings.Split(value, "=")
if len(parts) == 2 {
values[parts[0]] = parts[1]
}
}
return values
}

// FetchRedisInfo returns a map of requested stats.
func FetchRedisInfo(stat string, c rd.Conn) (map[string]string, error) {
out, err := rd.String(c.Do("INFO", stat))
Expand Down