// Package redis ... // // Description : redis 系统信息监控 // // Author : go_developer@163.com<白茶清欢> // // Date : 2021-11-27 12:22 下午 package redis import ( "context" "strings" "git.zhangdeman.cn/zhangdeman/util" redisClient "github.com/redis/go-redis/v9" yml "gopkg.in/yaml.v3" ) // GetRedisServerInfo 获取 redis server info // // Author : go_developer@163.com<白茶清欢> // // Date : 12:24 下午 2021/11/27 func GetRedisServerInfo(client *redisClient.ClusterClient) (*ServerInfo, error) { var result ServerInfo if err := infoToStruct(client, "server", &result); nil != err { return nil, err } return &result, nil } // GetMemoryInfo 获取内存信息 // // Author : go_developer@163.com<白茶清欢> // // Date : 12:59 下午 2021/11/27 func GetMemoryInfo(client *redisClient.ClusterClient) (*MemoryInfo, error) { var result MemoryInfo if err := infoToStruct(client, "memory", &result); nil != err { return nil, err } return &result, nil } // GetClientInfo 获取客户端信息 // // Author : go_developer@163.com<白茶清欢> // // Date : 1:10 下午 2021/11/27 func GetClientInfo(client *redisClient.ClusterClient) (*ClientInfo, error) { var result ClientInfo if err := infoToStruct(client, "clients", &result); nil != err { return nil, err } return &result, nil } // GetPersistence 获取持久化相关信息 // // Author : go_developer@163.com<白茶清欢> // // Date : 1:11 下午 2021/11/27 func GetPersistence(client *redisClient.ClusterClient) (*Persistence, error) { var result Persistence if err := infoToStruct(client, "persistence", &result); nil != err { return nil, err } return &result, nil } // GetStats 获取状态 // // Author : go_developer@163.com<白茶清欢> // // Date : 1:19 下午 2021/11/27 func GetStats(client *redisClient.ClusterClient) (*Stats, error) { var result Stats if err := infoToStruct(client, "stats", &result); nil != err { return nil, err } return &result, nil } // GetReplication 复制相关信息 // // Author : go_developer@163.com<白茶清欢> // // Date : 1:23 下午 2021/11/27 func GetReplication(client *redisClient.ClusterClient) (*Replication, error) { var result Replication if err := infoToStruct(client, "replication", &result); nil != err { return nil, err } result.SlaveList = GetSlaveList(client) return &result, nil } // GetSlaveList 获取从库信息 // // Author : go_developer@163.com<白茶清欢> // // Date : 4:26 下午 2021/11/27 func GetSlaveList(client *redisClient.ClusterClient) []SlaveNode { // 解析从库信息 slaveList := make([]SlaveNode, 0) var data map[string]string _ = infoToStruct(client, "replication", &data) slaveKey := []string{"slave0", "slave1", "slave2", "slave3", "slave4", "slave5", "slave6", "slave7", "slave8", "slave9"} for k, v := range data { isSlave := false for _, item := range slaveKey { if strings.Contains(k, item) { isSlave = true break } } if !isSlave { continue } vArr := strings.Split(v, ",") if len(vArr) < 3 { continue } slave := SlaveNode{ ID: k, IP: "", Port: 0, State: "", Offset: 0, Lag: 0, } for _, prop := range vArr { propArr := strings.Split(prop, "=") if len(propArr) != 2 { continue } switch strings.ToLower(propArr[0]) { case "ip": slave.IP = propArr[1] case "port": _ = util.ConvertAssign(&slave.Port, propArr[1]) case "state": slave.State = propArr[1] case "offset": _ = util.ConvertAssign(&slave.Offset, propArr[1]) case "lag": _ = util.ConvertAssign(&slave.Lag, propArr[1]) } } slaveList = append(slaveList, slave) } return slaveList } // GetCPUInfo 获取cpu信息 // // Author : go_developer@163.com<白茶清欢> // // Date : 1:24 下午 2021/11/27 func GetCPUInfo(client *redisClient.ClusterClient) (*CPU, error) { var result CPU if err := infoToStruct(client, "cpu", &result); nil != err { return nil, err } return &result, nil } // GetCommandStats 命令状态 // // Author : go_developer@163.com<白茶清欢> // // Date : 1:27 下午 2021/11/27 func GetCommandStats(client *redisClient.ClusterClient) (*Stats, error) { var result Stats if err := infoToStruct(client, "stats", &result); nil != err { return nil, err } return &result, nil } // GetCommandInfo 获取命令信息 // // Author : go_developer@163.com<白茶清欢> // // Date : 1:32 下午 2021/11/27 func GetCommandInfo(client *redisClient.ClusterClient) ([]CmdStat, error) { var result map[string]string if err := infoToStruct(client, "commandstats", &result); nil != err { return make([]CmdStat, 0), err } cmdList := make([]CmdStat, 0) // 解析数据 for cmd, detail := range result { infoArr := strings.Split(detail, ",") if len(infoArr) < 2 { // 去掉开始的描述信息 continue } info := CmdStat{ Cmd: strings.ReplaceAll(strings.ToLower(cmd), "cmdstat_", ""), Calls: 0, TotalUsedTime: 0, AvgUsedTime: 0, RejectedCalls: 0, FailedCalls: 0, SuccessCalls: 0, } for _, item := range infoArr { itemArr := strings.Split(item, "=") if len(itemArr) != 2 { continue } switch strings.ToLower(itemArr[0]) { case "calls": _ = util.ConvertAssign(&info.Calls, itemArr[1]) case "usec": _ = util.ConvertAssign(&info.TotalUsedTime, itemArr[1]) case "usec_per_call": _ = util.ConvertAssign(&info.AvgUsedTime, itemArr[1]) case "rejected_calls": _ = util.ConvertAssign(&info.RejectedCalls, itemArr[1]) case "failed_calls": _ = util.ConvertAssign(&info.FailedCalls, itemArr[1]) } } info.SuccessCalls = info.Calls - info.FailedCalls - info.RejectedCalls cmdList = append(cmdList, info) } return cmdList, nil } // GetKeyspace 获取 keyspace 信息 // // Author : go_developer@163.com<白茶清欢> // // Date : 2:44 下午 2021/11/27 func GetKeyspace(client *redisClient.ClusterClient) ([]DB, error) { var result map[string]string if err := infoToStruct(client, "keyspace", &result); nil != err { return make([]DB, 0), err } dbList := make([]DB, 0) for dbName, item := range result { itemArr := strings.Split(item, ",") if len(itemArr) < 3 { continue } dbInfo := DB{ Name: dbName, Keys: 0, Expires: 0, AvgTTL: 0, } for _, kv := range itemArr { kvArr := strings.Split(kv, "=") if len(kvArr) != 2 { continue } switch strings.ToLower(kvArr[0]) { case "keys": _ = util.ConvertAssign(&dbInfo.Keys, kvArr[1]) case "expires": _ = util.ConvertAssign(&dbInfo.Expires, kvArr[1]) case "avg_ttl": _ = util.ConvertAssign(&dbInfo.AvgTTL, kvArr[1]) } } dbList = append(dbList, dbInfo) } return dbList, nil } // GetCluster 获取 cluster 信息 // // Author : go_developer@163.com<白茶清欢> // // Date : 3:30 下午 2021/11/27 func GetCluster(client *redisClient.ClusterClient) (*Cluster, error) { var result Cluster if err := infoToStruct(client, "cluster", &result); nil != err { return nil, err } return &result, nil } // GetErrorStats 获取错误状态信息 // // Author : go_developer@163.com<白茶清欢> // // Date : 3:35 下午 2021/11/27 func GetErrorStats(client *redisClient.ClusterClient) ([]Error, error) { var result map[string]string if err := infoToStruct(client, "errorstats", &result); nil != err { return make([]Error, 0), err } errList := make([]Error, 0) for errType, item := range result { itemArr := strings.Split(item, "=") if len(itemArr) != 2 { continue } errInfo := Error{ Type: strings.ReplaceAll(errType, "errorstat_", ""), Count: 0, } _ = util.ConvertAssign(&errInfo.Count, itemArr[1]) errList = append(errList, errInfo) } return errList, nil } // infoToStruct 读取到的数据,解析到结构体 // // Author : go_developer@163.com<白茶清欢> // // Date : 12:28 下午 2021/11/27 func infoToStruct(client *redisClient.ClusterClient, module string, receiver interface{}) error { data := client.Info(context.Background(), module).String() // yaml 文件规范要求, key: val , 注意 : 的后面有空格 data = strings.ReplaceAll(data, ":", ": ") return yml.Unmarshal([]byte(data), receiver) }