2022-06-15 11:50:17 +08:00
|
|
|
// 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"
|
|
|
|
|
2023-08-16 11:33:55 +08:00
|
|
|
yml "gopkg.in/yaml.v3"
|
2022-06-15 11:50:17 +08:00
|
|
|
|
|
|
|
"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":
|
|
|
|
_ = 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 *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":
|
|
|
|
_ = 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 *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":
|
|
|
|
_ = 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 *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,
|
|
|
|
}
|
|
|
|
_ = 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 *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)
|
|
|
|
}
|