diff --git a/backend/services/connection_service.go b/backend/services/connection_service.go index 34378f9..cd61630 100644 --- a/backend/services/connection_service.go +++ b/backend/services/connection_service.go @@ -17,10 +17,10 @@ import ( ) type cmdHistoryItem struct { - timestamp int64 - Time string `json:"time"` + Timestamp int64 `json:"timestamp"` Server string `json:"server"` Cmd string `json:"cmd"` + Cost int64 `json:"cost"` } type connectionService struct { @@ -260,17 +260,17 @@ func (c *connectionService) getRedisClient(connName string, db int) (*redis.Clie ReadTimeout: time.Duration(selConn.ExecTimeout) * time.Second, WriteTimeout: time.Duration(selConn.ExecTimeout) * time.Second, }) - rdb.AddHook(redis2.NewHook(connName, func(cmd string) { + rdb.AddHook(redis2.NewHook(connName, func(cmd string, cost int64) { now := time.Now() - last := strings.LastIndex(cmd, ":") - if last != -1 { - cmd = cmd[:last] - } + //last := strings.LastIndex(cmd, ":") + //if last != -1 { + // cmd = cmd[:last] + //} c.cmdHistory = append(c.cmdHistory, cmdHistoryItem{ - timestamp: now.UnixMilli(), - Time: now.Format("2006-01-02 15:04:05"), + Timestamp: now.UnixMilli(), Server: connName, Cmd: cmd, + Cost: cost, }) })) @@ -287,7 +287,7 @@ func (c *connectionService) getRedisClient(connName string, db int) (*redis.Clie } if db >= 0 { - if err := rdb.Do(ctx, "SELECT", strconv.Itoa(db)).Err(); err != nil { + if err := rdb.Do(ctx, "select", strconv.Itoa(db)).Err(); err != nil { return nil, nil, err } } diff --git a/backend/utils/redis/log_hook.go b/backend/utils/redis/log_hook.go index 2bf096d..852edfb 100644 --- a/backend/utils/redis/log_hook.go +++ b/backend/utils/redis/log_hook.go @@ -2,12 +2,15 @@ package redis import ( "context" + "fmt" "github.com/redis/go-redis/v9" "log" "net" + "strconv" + "time" ) -type execCallback func(string) +type execCallback func(string, int64) type LogHook struct { name string @@ -21,28 +24,93 @@ func NewHook(name string, cmdExec execCallback) *LogHook { } } +func appendArg(b []byte, v interface{}) []byte { + switch v := v.(type) { + case nil: + return append(b, ""...) + case string: + return append(b, []byte(v)...) + case []byte: + return append(b, v...) + case int: + return strconv.AppendInt(b, int64(v), 10) + case int8: + return strconv.AppendInt(b, int64(v), 10) + case int16: + return strconv.AppendInt(b, int64(v), 10) + case int32: + return strconv.AppendInt(b, int64(v), 10) + case int64: + return strconv.AppendInt(b, v, 10) + case uint: + return strconv.AppendUint(b, uint64(v), 10) + case uint8: + return strconv.AppendUint(b, uint64(v), 10) + case uint16: + return strconv.AppendUint(b, uint64(v), 10) + case uint32: + return strconv.AppendUint(b, uint64(v), 10) + case uint64: + return strconv.AppendUint(b, v, 10) + case float32: + return strconv.AppendFloat(b, float64(v), 'f', -1, 64) + case float64: + return strconv.AppendFloat(b, v, 'f', -1, 64) + case bool: + if v { + return append(b, "true"...) + } + return append(b, "false"...) + case time.Time: + return v.AppendFormat(b, time.RFC3339Nano) + default: + return append(b, fmt.Sprint(v)...) + } +} + func (l *LogHook) DialHook(next redis.DialHook) redis.DialHook { return func(ctx context.Context, network, addr string) (net.Conn, error) { return next(ctx, network, addr) } } + func (l *LogHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook { return func(ctx context.Context, cmd redis.Cmder) error { log.Println(cmd) + t := time.Now() + err := next(ctx, cmd) if l.cmdExec != nil { - l.cmdExec(cmd.String()) + b := make([]byte, 0, 64) + for i, arg := range cmd.Args() { + if i > 0 { + b = append(b, ' ') + } + b = appendArg(b, arg) + } + l.cmdExec(string(b), time.Since(t).Milliseconds()) } - return next(ctx, cmd) + return err } } + func (l *LogHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook { return func(ctx context.Context, cmds []redis.Cmder) error { + t := time.Now() + err := next(ctx, cmds) + cost := time.Since(t).Milliseconds() for _, cmd := range cmds { log.Println("pipeline: ", cmd) if l.cmdExec != nil { - l.cmdExec(cmd.String()) + b := make([]byte, 0, 64) + for i, arg := range cmd.Args() { + if i > 0 { + b = append(b, ' ') + } + b = appendArg(b, arg) + } + l.cmdExec(string(b), cost) } } - return next(ctx, cmds) + return err } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9029b20..0086c11 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "frontend", "version": "0.0.0", "dependencies": { + "dayjs": "^1.11.9", "highlight.js": "^11.8.0", "lodash": "^4.17.21", "pinia": "^2.1.4", @@ -963,6 +964,11 @@ "date-fns": ">=2.0.0" } }, + "node_modules/dayjs": { + "version": "1.11.9", + "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.9.tgz", + "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", @@ -2694,6 +2700,11 @@ "dev": true, "requires": {} }, + "dayjs": { + "version": "1.11.9", + "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.9.tgz", + "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index c66ac07..87f7877 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,6 +9,7 @@ "preview": "vite preview" }, "dependencies": { + "dayjs": "^1.11.9", "highlight.js": "^11.8.0", "lodash": "^4.17.21", "pinia": "^2.1.4", diff --git a/frontend/src/components/common/RedisTypeTag.vue b/frontend/src/components/common/RedisTypeTag.vue index 09e46b7..6927e8a 100644 --- a/frontend/src/components/common/RedisTypeTag.vue +++ b/frontend/src/components/common/RedisTypeTag.vue @@ -1,6 +1,6 @@