完成 Redis 监控的功能

This commit is contained in:
YunaiV
2021-01-28 01:34:49 +08:00
parent 842496a534
commit 46706eb069
15 changed files with 737 additions and 1051 deletions

View File

@ -1,5 +1,6 @@
package cn.iocoder.dashboard.framework.redis.core;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
@ -14,15 +15,23 @@ import java.time.Duration;
@Data
public class RedisKeyDefine {
@Getter
@AllArgsConstructor
public enum KeyTypeEnum {
STRING,
LIST,
HASH,
SET,
ZSET,
STREAM,
PUBSUB
STRING("String"),
LIST("List"),
HASH("Hash"),
SET("Set"),
ZSET("Sorted Set"),
STREAM("Stream"),
PUBSUB("Pub/Sub");
/**
* 类型
*/
@JsonValue
private final String type;
}
@ -37,6 +46,7 @@ public class RedisKeyDefine {
/**
* 类型
*/
@JsonValue
private final Integer type;
}
@ -63,25 +73,29 @@ public class RedisKeyDefine {
* 过期时间
*/
private final Duration timeout;
/**
* 备注
*/
private final String memo;
public RedisKeyDefine(String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, Duration timeout) {
private RedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType,
TimeoutTypeEnum timeoutType, Duration timeout) {
this.memo = memo;
this.keyTemplate = keyTemplate;
this.keyType = keyType;
this.valueType = valueType;
this.timeoutType = TimeoutTypeEnum.FIXED;
this.timeout = timeout;
this.timeoutType = timeoutType;
// 添加注册表
RedisKeyRegistry.add(this);
}
public RedisKeyDefine(String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, TimeoutTypeEnum timeoutType) {
this.keyTemplate = keyTemplate;
this.keyType = keyType;
this.valueType = valueType;
this.timeoutType = timeoutType;
this.timeout = Duration.ZERO;
// 添加注册表
RedisKeyRegistry.add(this);
public RedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, Duration timeout) {
this(memo, keyTemplate, keyType, valueType, TimeoutTypeEnum.FIXED, timeout);
}
public RedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, TimeoutTypeEnum timeoutType) {
this(memo, keyTemplate, keyType, valueType, timeoutType, Duration.ZERO);
}
}

View File

@ -8,6 +8,9 @@ import java.util.List;
*/
public class RedisKeyRegistry {
/**
* Redis RedisKeyDefine 数组
*/
private static final List<RedisKeyDefine> defines = new ArrayList<>();
public static void add(RedisKeyDefine define) {

View File

@ -1,25 +1,28 @@
package cn.iocoder.dashboard.modules.infra.controller.redis;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine;
import cn.iocoder.dashboard.framework.redis.core.RedisKeyRegistry;
import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisKeyRespVO;
import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisMonitorRespVO;
import cn.iocoder.dashboard.modules.infra.convert.redis.RedisConvert;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
@Api("Redis 监控 API")
@RestController
@RequestMapping("/infra/redis")
public class RedisController {
@ -27,7 +30,8 @@ public class RedisController {
@Resource
private StringRedisTemplate stringRedisTemplate;
// @PreAuthorize("@ss.hasPermission('infra:redis:get-monitor-info')")
@ApiOperation("获得 Redis 监控信息")
@PreAuthorize("@ss.hasPermission('infra:redis:get-monitor-info')")
@GetMapping("/get-monitor-info")
public CommonResult<InfRedisMonitorRespVO> getRedisMonitorInfo() {
// 获得 Redis 统计信息
@ -36,33 +40,16 @@ public class RedisController {
Properties commandStats = stringRedisTemplate.execute((
RedisCallback<Properties>) connection -> connection.info("commandstats"));
assert commandStats != null; // 断言,避免警告
// 拼接结果返回
InfRedisMonitorRespVO respVO = InfRedisMonitorRespVO.builder().info(info).dbSize(dbSize)
.commandStats(new ArrayList<>(commandStats.size())).build();
commandStats.forEach((key, value) -> {
respVO.getCommandStats().add(InfRedisMonitorRespVO.CommandStat.builder()
.command(StrUtil.subAfter((String) key, "cmdstat_", false))
.calls(Integer.valueOf(StrUtil.subBetween((String) value, "calls=", ",")))
.usec(Integer.valueOf(StrUtil.subBetween((String) value, "usec=", ",")))
.build());
});
return success(respVO);
return success(RedisConvert.INSTANCE.build(info, dbSize, commandStats));
}
// @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
@ApiOperation("获得 Redis Key 列表")
@PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
@GetMapping("/get-key-list")
public CommonResult<List<InfRedisKeyRespVO>> getKeyList() {
List<InfRedisKeyRespVO> respVOList = RedisKeyRegistry.list().stream()
.map(define -> InfRedisKeyRespVO.builder()
.keyTemplate(define.getKeyTemplate())
.keyType(define.getKeyType().name())
.valueType(define.getValueType().getName())
.timeoutType(define.getTimeoutType().getType())
.timeout((int) define.getTimeout().getSeconds())
.build())
.collect(Collectors.toList());
return success(respVOList);
List<RedisKeyDefine> keyDefines = RedisKeyRegistry.list();
return success(RedisConvert.INSTANCE.convertList(keyDefines));
}
}

View File

@ -1,33 +1,36 @@
package cn.iocoder.dashboard.modules.infra.controller.redis.vo;
import cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import java.time.Duration;
@ApiModel("Redis Key 信息 Response VO")
@Data
@Builder
@AllArgsConstructor
public class InfRedisKeyRespVO {
/**
* Key 模板
*/
private final String keyTemplate;
/**
* Key 类型的枚举
*/
private final String keyType;
/**
* Value 类型
*/
private final String valueType;
/**
* 超时类型
*/
private final Integer timeoutType;
/**
* 过期时间
*/
private final Integer timeout;
@ApiModelProperty(value = "login_user:%s", required = true, example = "String")
private String keyTemplate;
@ApiModelProperty(value = "Key 类型的枚举", required = true, example = "String")
private RedisKeyDefine.KeyTypeEnum keyType;
@ApiModelProperty(value = "Value 类型", required = true, example = "java.lang.String")
private Class valueType;
@ApiModelProperty(value = "超时类型", required = true, example = "1")
private RedisKeyDefine.TimeoutTypeEnum timeoutType;
@ApiModelProperty(value = "过期时间,单位:毫秒", required = true, example = "1024")
private Duration timeout;
@ApiModelProperty(value = "备注", required = true, example = "啦啦啦啦~")
private String memo;
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.dashboard.modules.infra.controller.redis.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -7,26 +9,34 @@ import lombok.Data;
import java.util.List;
import java.util.Properties;
@ApiModel("Redis 监控信息 Response VO")
@Data
@Builder
@AllArgsConstructor
public class InfRedisMonitorRespVO {
@ApiModelProperty(value = "Redis info 指令结果", required = true, notes = "具体字段,查看 Redis 文档")
private Properties info;
@ApiModelProperty(value = "Redis key 数量", required = true, example = "1024")
private Long dbSize;
private List<Object> commandStats;
@ApiModelProperty(value = "CommandStat 数组", required = true)
private List<CommandStat> commandStats;
@ApiModel("Redis 命令统计结果")
@Data
@Builder
@AllArgsConstructor
public static class CommandStat {
@ApiModelProperty(value = "Redis 命令", required = true, example = "get")
private String command;
@ApiModelProperty(value = "调用次数", required = true, example = "1024")
private Integer calls;
@ApiModelProperty(value = "消耗 CPU 秒数", required = true, example = "666")
private Integer usec;
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.dashboard.modules.infra.convert.redis;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine;
import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisKeyRespVO;
import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisMonitorRespVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
@Mapper
public interface RedisConvert {
RedisConvert INSTANCE = Mappers.getMapper(RedisConvert.class);
default InfRedisMonitorRespVO build(Properties info, Long dbSize, Properties commandStats) {
InfRedisMonitorRespVO respVO = InfRedisMonitorRespVO.builder().info(info).dbSize(dbSize)
.commandStats(new ArrayList<>(commandStats.size())).build();
commandStats.forEach((key, value) -> {
respVO.getCommandStats().add(InfRedisMonitorRespVO.CommandStat.builder()
.command(StrUtil.subAfter((String) key, "cmdstat_", false))
.calls(Integer.valueOf(StrUtil.subBetween((String) value, "calls=", ",")))
.usec(Integer.valueOf(StrUtil.subBetween((String) value, "usec=", ",")))
.build());
});
return respVO;
}
List<InfRedisKeyRespVO> convertList(List<RedisKeyDefine> list);
}

View File

@ -14,20 +14,12 @@ import static cn.iocoder.dashboard.framework.redis.core.RedisKeyDefine.KeyTypeEn
*/
public interface RedisKeyConstants {
/**
* {@link LoginUser} 的缓存
*
* key 的 format 的参数是 sessionId
*/
RedisKeyDefine LOGIN_USER = new RedisKeyDefine("login_user:%s", STRING, LoginUser.class,
Duration.ofMinutes(30));
RedisKeyDefine LOGIN_USER = new RedisKeyDefine("登陆用户的缓存",
"login_user:%s", // 参数为 sessionId
STRING, LoginUser.class, Duration.ofMinutes(30));
/**
* 验证码的缓存
*
* key 的 format 的参数是 uuid
*/
RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("captcha_code:%s", STRING, String.class,
RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("验证码的缓存",
"captcha_code:%s", // 参数为 uuid
STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
}