forked from mirror/redis
support for slowlog command
This commit is contained in:
parent
4306c58d43
commit
be9ae84c6f
113
command.go
113
command.go
|
@ -2167,3 +2167,116 @@ func (c *cmdsInfoCache) Get() (map[string]*CommandInfo, error) {
|
||||||
})
|
})
|
||||||
return c.cmds, err
|
return c.cmds, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type SlowLog struct {
|
||||||
|
ID int64
|
||||||
|
CreatedAt time.Time
|
||||||
|
Costs time.Duration
|
||||||
|
/*
|
||||||
|
ClientAddress,ClientName
|
||||||
|
There are also optional fields emitted only by Redis 4.0 or greater:
|
||||||
|
https://redis.io/commands/slowlog#output-format
|
||||||
|
*/
|
||||||
|
ClientAddress, ClientName string
|
||||||
|
Args []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SlowLogCmd struct {
|
||||||
|
baseCmd
|
||||||
|
|
||||||
|
val []SlowLog
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Cmder = (*SlowLogCmd)(nil)
|
||||||
|
|
||||||
|
func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd {
|
||||||
|
return &SlowLogCmd{
|
||||||
|
baseCmd: baseCmd{
|
||||||
|
ctx: ctx,
|
||||||
|
args: args,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *SlowLogCmd) Val() []SlowLog {
|
||||||
|
return cmd.val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *SlowLogCmd) Result() ([]SlowLog, error) {
|
||||||
|
return cmd.Val(), cmd.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *SlowLogCmd) String() string {
|
||||||
|
return cmdString(cmd, cmd.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error {
|
||||||
|
_, cmd.err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
|
||||||
|
cmd.val = make([]SlowLog, n)
|
||||||
|
for i := 0; i < len(cmd.val); i++ {
|
||||||
|
n, err := rd.ReadArrayLen()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n < 4 {
|
||||||
|
err := fmt.Errorf("redis: got %d elements in slowlog get, expected at least 4", n)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := rd.ReadIntReply()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
createdAt, err := rd.ReadIntReply()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
createdAtTime := time.Unix(createdAt, 0)
|
||||||
|
costs, err := rd.ReadIntReply()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
costsDuration := time.Duration(costs) * time.Microsecond
|
||||||
|
cmdLen, err := rd.ReadArrayLen()
|
||||||
|
if cmdLen < 1 {
|
||||||
|
err := fmt.Errorf("redis: got %d elements commands reply in slowlog get, expected at least 1", cmdLen)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cmdString := make([]string, cmdLen)
|
||||||
|
for i := 0; i < int(cmdLen); i++ {
|
||||||
|
cmdString[i], err = rd.ReadString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var address, name string
|
||||||
|
for i := 4; i < int(n); i++ {
|
||||||
|
str, err := rd.ReadString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if i == 4 {
|
||||||
|
address = str
|
||||||
|
} else if i == 5 {
|
||||||
|
name = str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.val[i] = SlowLog{
|
||||||
|
ID: id,
|
||||||
|
CreatedAt: createdAtTime,
|
||||||
|
Costs: costsDuration,
|
||||||
|
Args: cmdString,
|
||||||
|
ClientAddress: address,
|
||||||
|
ClientName: name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
})
|
||||||
|
return cmd.err
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8/internal"
|
"github.com/go-redis/redis/v8/internal"
|
||||||
|
@ -2306,8 +2307,11 @@ func (c cmdable) SlaveOf(ctx context.Context, host, port string) *StatusCmd {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c cmdable) SlowLog(ctx context.Context) {
|
func (c cmdable) SlowLog(ctx context.Context, num int64) *SlowLogCmd {
|
||||||
panic("not implemented")
|
n := strconv.FormatInt(num, 10)
|
||||||
|
cmd := NewSlowLogCmd(context.Background(), "slowlog", "get", n)
|
||||||
|
_ = c(ctx, cmd)
|
||||||
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c cmdable) Sync(ctx context.Context) {
|
func (c cmdable) Sync(ctx context.Context) {
|
||||||
|
|
|
@ -4013,6 +4013,24 @@ var _ = Describe("Commands", func() {
|
||||||
Expect(vals).To(Equal([]interface{}{int64(12), proto.RedisError("error"), "abc"}))
|
Expect(vals).To(Equal([]interface{}{int64(12), proto.RedisError("error"), "abc"}))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Describe("SlowLog", func() {
|
||||||
|
It("returns slow query result", func() {
|
||||||
|
var CONFIGSLOWKEY string = "slowlog-log-slower-than"
|
||||||
|
old := client.ConfigGet(ctx, CONFIGSLOWKEY).Val()
|
||||||
|
client.ConfigSet(ctx, CONFIGSLOWKEY, "0")
|
||||||
|
defer client.ConfigSet(ctx, CONFIGSLOWKEY, old[1].(string))
|
||||||
|
_, e := client.Eval(ctx, "redis.call('slowlog','reset')", []string{}).Result()
|
||||||
|
if e != nil && e != redis.Nil {
|
||||||
|
fmt.Println(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client.Set(ctx, "test", "true", 0)
|
||||||
|
result, err := client.SlowLog(ctx, -1).Result()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(len(result)).To(Equal(3))
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
type numberStruct struct {
|
type numberStruct struct {
|
||||||
|
|
|
@ -510,3 +510,21 @@ func ExampleNewUniversalClient_cluster() {
|
||||||
|
|
||||||
rdb.Ping(ctx)
|
rdb.Ping(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleClient_SlowLog() {
|
||||||
|
var (
|
||||||
|
CONFIGSLOWKEY string = "slowlog-log-slower-than"
|
||||||
|
)
|
||||||
|
old := rdb.ConfigGet(ctx, CONFIGSLOWKEY).Val()
|
||||||
|
rdb.ConfigSet(ctx, CONFIGSLOWKEY, "0")
|
||||||
|
defer rdb.ConfigSet(ctx, CONFIGSLOWKEY, old[1].(string))
|
||||||
|
_, e := rdb.Eval(ctx, "redis.call('slowlog','reset')", []string{}).Result()
|
||||||
|
if e != nil && e != redis.Nil {
|
||||||
|
fmt.Println(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rdb.Set(ctx, "test", "true", 0)
|
||||||
|
result, err := rdb.SlowLog(ctx, -1).Result()
|
||||||
|
fmt.Println(len(result), err)
|
||||||
|
// Output: 3 <nil>
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue