From b68976d3c5cfbc7bde111531f563d20a15d9c947 Mon Sep 17 00:00:00 2001 From: Yoofi Quansah Date: Wed, 30 Sep 2020 09:36:45 -0700 Subject: [PATCH] feat: add functionality to get values from redis commands (#8196) --- go.mod | 2 +- go.sum | 4 +-- plugins/inputs/redis/README.md | 5 ++++ plugins/inputs/redis/redis.go | 46 ++++++++++++++++++++++++++++++ plugins/inputs/redis/redis_test.go | 43 ++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index af30e1486c73b..9d1a82d7d90a0 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/glinton/ping v0.1.4-0.20200311211934-5ac87da8cd96 github.com/go-logfmt/logfmt v0.4.0 github.com/go-ole/go-ole v1.2.1 // indirect - github.com/go-redis/redis v6.12.0+incompatible + github.com/go-redis/redis v6.15.9+incompatible github.com/go-sql-driver/mysql v1.5.0 github.com/goburrow/modbus v0.1.0 github.com/goburrow/serial v0.1.0 // indirect diff --git a/go.sum b/go.sum index 926465d5914af..40662f6386a72 100644 --- a/go.sum +++ b/go.sum @@ -214,8 +214,8 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+ github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-redis/redis v6.12.0+incompatible h1:s+64XI+z/RXqGHz2fQSgRJOEwqqSXeX3dliF7iVkMbE= -github.com/go-redis/redis v6.12.0+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= diff --git a/plugins/inputs/redis/README.md b/plugins/inputs/redis/README.md index f62b9db6e3f61..c8f343b262aca 100644 --- a/plugins/inputs/redis/README.md +++ b/plugins/inputs/redis/README.md @@ -14,6 +14,11 @@ ## If no servers are specified, then localhost is used as the host. ## If no port is specified, 6379 is used servers = ["tcp://localhost:6379"] + ## Optional. Specify redis commands to retrieve values + # [[inputs.redis.commands]] + # command = ["get", "sample-key"] + # field = "sample-key-value" + # type = "string" ## specify server password # password = "s#cr@t%" diff --git a/plugins/inputs/redis/redis.go b/plugins/inputs/redis/redis.go index 5e32afef5c65f..3a76a351c05de 100644 --- a/plugins/inputs/redis/redis.go +++ b/plugins/inputs/redis/redis.go @@ -17,7 +17,14 @@ import ( "github.com/influxdata/telegraf/plugins/inputs" ) +type RedisCommand struct { + Command []interface{} + Field string + Type string +} + type Redis struct { + Commands []*RedisCommand Servers []string Password string tls.ClientConfig @@ -29,6 +36,7 @@ type Redis struct { } type Client interface { + Do(returnType string, args ...interface{}) (interface{}, error) Info() *redis.StringCmd BaseTags() map[string]string } @@ -38,6 +46,21 @@ type RedisClient struct { tags map[string]string } +func (r *RedisClient) Do(returnType string, args ...interface{}) (interface{}, error) { + rawVal := r.client.Do(args...) + + switch returnType { + case "integer": + return rawVal.Int64() + case "string": + return rawVal.String() + case "float": + return rawVal.Float64() + default: + return rawVal.String() + } +} + func (r *RedisClient) Info() *redis.StringCmd { return r.client.Info("ALL") } @@ -64,6 +87,12 @@ var sampleConfig = ` ## If no port is specified, 6379 is used servers = ["tcp://localhost:6379"] + ## Optional. Specify redis commands to retrieve values + # [[inputs.redis.commands]] + # command = ["get", "sample-key"] + # field = "sample-key-value" + # type = "string" + ## specify server password # password = "s#cr@t%" @@ -179,6 +208,7 @@ func (r *Redis) Gather(acc telegraf.Accumulator) error { go func(client Client) { defer wg.Done() acc.AddError(r.gatherServer(client, acc)) + acc.AddError(r.gatherCommandValues(client, acc)) }(client) } @@ -186,6 +216,22 @@ func (r *Redis) Gather(acc telegraf.Accumulator) error { return nil } +func (r *Redis) gatherCommandValues(client Client, acc telegraf.Accumulator) error { + fields := make(map[string]interface{}) + for _, command := range r.Commands { + val, err := client.Do(command.Type, command.Command...) + if err != nil { + return err + } + + fields[command.Field] = val + } + + acc.AddFields("redis_commands", fields, client.BaseTags()) + + return nil +} + func (r *Redis) gatherServer(client Client, acc telegraf.Accumulator) error { info, err := client.Info().Result() if err != nil { diff --git a/plugins/inputs/redis/redis_test.go b/plugins/inputs/redis/redis_test.go index 637b464f95e99..d5aaa7a7bfa38 100644 --- a/plugins/inputs/redis/redis_test.go +++ b/plugins/inputs/redis/redis_test.go @@ -7,11 +7,27 @@ import ( "testing" "time" + "github.com/go-redis/redis" "github.com/influxdata/telegraf/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +type testClient struct { +} + +func (t *testClient) BaseTags() map[string]string { + return map[string]string{"host": "redis.net"} +} + +func (t *testClient) Info() *redis.StringCmd { + return nil +} + +func (t *testClient) Do(returnType string, args ...interface{}) (interface{}, error) { + return 2, nil +} + func TestRedisConnect(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") @@ -30,6 +46,33 @@ func TestRedisConnect(t *testing.T) { require.NoError(t, err) } +func TestRedis_Commands(t *testing.T) { + const redisListKey = "test-list-length" + var acc testutil.Accumulator + + tc := &testClient{} + + rc := &RedisCommand{ + Command: []interface{}{"llen", "test-list"}, + Field: redisListKey, + Type: "integer", + } + + r := &Redis{ + Commands: []*RedisCommand{rc}, + clients: []Client{tc}, + } + + err := r.gatherCommandValues(tc, &acc) + require.NoError(t, err) + + fields := map[string]interface{}{ + redisListKey: 2, + } + + acc.AssertContainsFields(t, "redis_commands", fields) +} + func TestRedis_ParseMetrics(t *testing.T) { var acc testutil.Accumulator tags := map[string]string{"host": "redis.net"}