feature/redis #9
326
middleware/redis/monitor.go
Normal file
326
middleware/redis/monitor.go
Normal file
@ -0,0 +1,326 @@
|
||||
// Package redis ...
|
||||
//
|
||||
// Description : redis 系统信息监控
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2021-11-27 12:22 下午
|
||||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"git.zhangdeman.cn/zhangdeman/gopkg/convert"
|
||||
|
||||
yml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
// GetRedisServerInfo 获取 redis server info
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:24 下午 2021/11/27
|
||||
func GetRedisServerInfo(client *redis.Client) (*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 *redis.Client) (*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 *redis.Client) (*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 *redis.Client) (*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 *redis.Client) (*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 *redis.Client) (*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 *redis.Client) []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":
|
||||
_ = convert.ConvertAssign(&slave.Port, propArr[1])
|
||||
case "state":
|
||||
slave.State = propArr[1]
|
||||
case "offset":
|
||||
_ = convert.ConvertAssign(&slave.Offset, propArr[1])
|
||||
case "lag":
|
||||
_ = convert.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 *redis.Client) (*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 *redis.Client) (*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 *redis.Client) ([]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":
|
||||
_ = convert.ConvertAssign(&info.Calls, itemArr[1])
|
||||
case "usec":
|
||||
_ = convert.ConvertAssign(&info.TotalUsedTime, itemArr[1])
|
||||
case "usec_per_call":
|
||||
_ = convert.ConvertAssign(&info.AvgUsedTime, itemArr[1])
|
||||
case "rejected_calls":
|
||||
_ = convert.ConvertAssign(&info.RejectedCalls, itemArr[1])
|
||||
case "failed_calls":
|
||||
_ = convert.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 *redis.Client) ([]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":
|
||||
_ = convert.ConvertAssign(&dbInfo.Keys, kvArr[1])
|
||||
case "expires":
|
||||
_ = convert.ConvertAssign(&dbInfo.Expires, kvArr[1])
|
||||
case "avg_ttl":
|
||||
_ = convert.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 *redis.Client) (*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 *redis.Client) ([]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,
|
||||
}
|
||||
_ = convert.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 *redis.Client, 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)
|
||||
}
|
@ -42,6 +42,12 @@ func TestCommandProxy(t *testing.T) {
|
||||
panic(err.Error())
|
||||
}
|
||||
r, cmdErr := instance.CommandProxy(nil, "test_redis", "set", "command_proxy", "hello world")
|
||||
c, _ := instance.GetRedisClient("test_redis")
|
||||
fmt.Println(GetRedisServerInfo(c.Instance))
|
||||
fmt.Println(GetCommandInfo(c.Instance))
|
||||
fmt.Println(GetKeyspace(c.Instance))
|
||||
fmt.Println(GetCluster(c.Instance))
|
||||
fmt.Println(GetErrorStats(c.Instance))
|
||||
assert.Nil(t, cmdErr, "命令执行成功")
|
||||
assert.Equal(t, "OK", fmt.Sprintf("%v", r))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user