From c731409c06626f7d64e20b93f023870c5c06d4b9 Mon Sep 17 00:00:00 2001 From: Leo <98382335+gaoziman@users.noreply.github.com> Date: Sun, 28 Sep 2025 00:08:37 +0800 Subject: [PATCH] =?UTF-8?q?feat(monitor):=20=E5=AE=9E=E7=8E=B0=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E7=9B=91=E6=8E=A7=E6=A8=A1=E5=9D=97=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加服务器资源监控功能(CPU、内存、磁盘、JVM) - 实现Redis监控和性能统计 - 添加缓存管理功能(查看、删除、清空) - 使用OSHI库进行跨平台硬件信息收集 - 集成Sa-Token权限验证和Swagger文档 - 支持实时监控数据获取和格式化显示 --- .../coder-common-thin-monitor/pom.xml | 65 ++++++ .../monitor/controller/CacheController.java | 134 ++++++++++++ .../monitor/controller/RedisController.java | 63 ++++++ .../monitor/controller/ServerController.java | 34 +++ .../thin/monitor/pojo/server/Cpu.java | 120 +++++++++++ .../thin/monitor/pojo/server/Jvm.java | 155 ++++++++++++++ .../thin/monitor/pojo/server/Mem.java | 105 +++++++++ .../thin/monitor/pojo/server/Server.java | 202 ++++++++++++++++++ .../thin/monitor/pojo/server/Sys.java | 36 ++++ .../thin/monitor/pojo/server/SysCache.java | 52 +++++ .../thin/monitor/pojo/server/SysFile.java | 46 ++++ 11 files changed, 1012 insertions(+) create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/pom.xml create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/CacheController.java create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/RedisController.java create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/ServerController.java create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Cpu.java create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Jvm.java create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Mem.java create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Server.java create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Sys.java create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/SysCache.java create mode 100644 coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/SysFile.java diff --git a/coder-common-thin-modules/coder-common-thin-monitor/pom.xml b/coder-common-thin-modules/coder-common-thin-monitor/pom.xml new file mode 100644 index 0000000..d553303 --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + + org.leocoder.thin + coder-common-thin-backend + ${revision} + ../../pom.xml + + + coder-common-thin-monitor + coder-common-thin-monitor + 系统监控模块:服务器资源监控、Redis监控、缓存管理等功能 + + + + + org.leocoder.thin + coder-common-thin-common + ${revision} + + + + + org.leocoder.thin + coder-common-thin-resultex + ${revision} + + + + + org.leocoder.thin + coder-common-thin-sa-token + ${revision} + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + com.github.oshi + oshi-core + 6.4.10 + + + + + org.apache.commons + commons-lang3 + + + + \ No newline at end of file diff --git a/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/CacheController.java b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/CacheController.java new file mode 100644 index 0000000..b51998b --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/CacheController.java @@ -0,0 +1,134 @@ +package org.leocoder.thin.monitor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.leocoder.thin.monitor.pojo.server.SysCache; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * @author Leocoder + * @description [缓存管理] + */ +@Tag(name = "缓存管理", description = "Redis缓存管理,包括缓存查看、删除、清空等操作") +@RestController +@RequestMapping("/coder/monitor") +@RequiredArgsConstructor +public class CacheController { + + private final RedisTemplate redisTemplate; + + private final static List cacheList = new ArrayList<>(); + + static { + cacheList.add(new SysCache("Authorization:login:session:", "用户登录信息")); + cacheList.add(new SysCache("coderDict:", "数据字典")); + cacheList.add(new SysCache("coderCaptchaCodes:", "验证码")); + cacheList.add(new SysCache("repeat_submit:", "防重提交")); + cacheList.add(new SysCache("rate_limit:", "限流处理")); + cacheList.add(new SysCache("pwd_error:", "密码错误次数")); + cacheList.add(new SysCache("coderBlacklistIp:", "黑名单IP")); + } + + /** + * @description [查询Redis缓存所有Key] + * @author Leocoder + */ + @Operation(summary = "查询Redis缓存所有Key", description = "获取系统中所有缓存分类的Key列表") + @SaCheckPermission("monitor:cache:list") + @GetMapping("/cache/getRedisCache") + public List getRedisInformation() { + return cacheList; + } + + /** + * @description [查询Redis缓存键名列表] + * @author Leocoder + */ + @Operation(summary = "查询Redis缓存键名列表", description = "根据缓存名称获取对应的键名列表") + @SaCheckPermission("monitor:cache:list") + @GetMapping("/cache/getCacheKeys/{cacheName}") + public TreeSet getCacheKeys(@PathVariable("cacheName") String cacheName) { + Set cacheKeys = redisTemplate.keys(cacheName + "*"); + if (ObjectUtils.isEmpty(cacheKeys)) { + return new TreeSet<>(); + } + return new TreeSet<>(cacheKeys); + } + + /** + * @description [获取Redis缓存内容] + * @author Leocoder + */ + @Operation(summary = "获取Redis缓存内容", description = "根据缓存键名获取缓存内容和过期时间") + @SaCheckPermission("monitor:cache:list") + @PostMapping("/cache/getValue") + public SysCache getCacheValue(@RequestBody SysCache sysCache) { + Boolean hasKey = redisTemplate.hasKey(sysCache.getCacheKey()); + if (!hasKey) { + return new SysCache(sysCache.getCacheName(), sysCache.getCacheKey(), "", ""); + } + String cacheValue = redisTemplate.opsForValue().get(sysCache.getCacheKey()); + Long cacheTime = redisTemplate.getExpire(sysCache.getCacheKey(), TimeUnit.SECONDS); + String formatCacheTime = ""; + if (cacheTime != null) { + if (cacheTime == -1L) { + formatCacheTime = "不过期"; + } else { + int hours = (int) (cacheTime / 3600); + int minutes = (int) ((cacheTime % 3600) / 60); + int seconds = (int) (cacheTime % 60); + formatCacheTime = String.format("%02d小时%02d分钟%02d秒", hours, minutes, seconds); + } + } + return new SysCache(sysCache.getCacheName(), sysCache.getCacheKey(), cacheValue, formatCacheTime); + } + + /** + * @description [删除Redis指定名称缓存] + * @author Leocoder + */ + @Operation(summary = "删除Redis指定名称缓存", description = "根据缓存名称前缀删除所有相关缓存") + @SaCheckPermission("monitor:cache:delete") + @PostMapping("/cache/deleteCacheName/{cacheName}") + public void deleteCacheName(@PathVariable("cacheName") String cacheName) { + Collection cacheKeys = redisTemplate.keys(cacheName + "*"); + if (ObjectUtils.isNotEmpty(cacheKeys)) { + redisTemplate.delete(cacheKeys); + } + } + + /** + * @description [删除Redis指定键名缓存] + * @author Leocoder + */ + @Operation(summary = "删除Redis指定键名缓存", description = "根据具体的缓存键名删除单个缓存") + @SaCheckPermission("monitor:cache:delete") + @PostMapping("/cache/deleteCacheKey") + public void deleteCacheKey(@RequestBody SysCache sysCache) { + if (StringUtils.isNotBlank(sysCache.getCacheKey())) { + redisTemplate.delete(sysCache.getCacheKey()); + } + } + + /** + * @description [删除Redis所有信息] + * @author Leocoder + */ + @Operation(summary = "删除Redis所有信息", description = "清空Redis中的所有缓存数据(谨慎操作)") + @SaCheckPermission("monitor:cache:clear") + @PostMapping("/cache/deleteCacheAll") + public void deleteCacheAll() { + Collection cacheKeys = redisTemplate.keys("*"); + if (ObjectUtils.isNotEmpty(cacheKeys)) { + redisTemplate.delete(cacheKeys); + } + } +} \ No newline at end of file diff --git a/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/RedisController.java b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/RedisController.java new file mode 100644 index 0000000..46d1e73 --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/RedisController.java @@ -0,0 +1,63 @@ +package org.leocoder.thin.monitor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * @author Leocoder + * @description [Redis监控] + */ +@Tag(name = "Redis监控", description = "Redis数据库监控,包括连接信息、内存使用、命令统计等") +@RestController +@RequestMapping("/coder/monitor") +@RequiredArgsConstructor +public class RedisController { + + private final RedisTemplate redisTemplate; + + /** + * @description [获取Redis监控信息] + * @author Leocoder + */ + @Operation(summary = "获取Redis监控信息", description = "获取Redis服务器监控数据,包括服务信息、内存使用、连接数、命令统计等") + @SaCheckPermission("monitor:redis:list") + @GetMapping("/redis/getRedisInformation") + public Map getRedisInformation() { + try { + Properties info = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info()); + Properties commandStats = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info("commandstats")); + Object dbSize = redisTemplate.execute((RedisCallback) connection -> connection.dbSize()); + + Map result = new HashMap<>(3); + result.put("info", info); + result.put("dbSize", dbSize); + + List> pieList = new ArrayList<>(); + if (commandStats != null) { + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(2); + String propertyValue = commandStats.getProperty(key); + data.put("name", StringUtils.removeStart(key, "cmdstat_")); + data.put("value", StringUtils.substringBetween(propertyValue, "calls=", ",usec")); + pieList.add(data); + }); + } + result.put("commandStats", pieList); + return result; + } catch (Exception e) { + Map errorResult = new HashMap<>(); + errorResult.put("error", "获取Redis监控信息失败: " + e.getMessage()); + return errorResult; + } + } +} \ No newline at end of file diff --git a/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/ServerController.java b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/ServerController.java new file mode 100644 index 0000000..a08bfc7 --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/controller/ServerController.java @@ -0,0 +1,34 @@ +package org.leocoder.thin.monitor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.leocoder.thin.monitor.pojo.server.Server; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author Leocoder + * @description [服务器监控] + */ +@Tag(name = "服务器监控", description = "系统服务器资源监控,包括CPU、内存、磁盘、JVM等信息") +@RestController +@RequestMapping("/coder/monitor") +@RequiredArgsConstructor +public class ServerController { + + /** + * @description [获取服务器监控信息] + * @author Leocoder + */ + @Operation(summary = "获取服务器监控信息", description = "获取服务器实时监控数据,包括CPU使用率、内存使用情况、磁盘空间、JVM状态等") + @SaCheckPermission("monitor:server:list") + @GetMapping("/server/getServerInformation") + public Server getServerInformation() { + Server server = new Server(); + server.copyTo(); + return server; + } +} \ No newline at end of file diff --git a/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Cpu.java b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Cpu.java new file mode 100644 index 0000000..e502958 --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Cpu.java @@ -0,0 +1,120 @@ +package org.leocoder.thin.monitor.pojo.server; + +import lombok.Data; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * @author Leocoder + * @description [CPU相关信息] + */ +@Data +public class Cpu { + + /** + * 核心数 + */ + private int cpuNum; + + /** + * CPU总的使用率 + */ + private double total; + + /** + * CPU系统使用率 + */ + private double sys; + + /** + * CPU用户使用率 + */ + private double used; + + /** + * CPU当前等待率 + */ + private double wait; + + /** + * CPU当前空闲率 + */ + private double free; + + /** + * @description [获取CPU使用率] + * @author Leocoder + */ + public double getCpuUsage() { + if (total > 0) { + return multiply(divide(total - free, total, 4), 100); + } + return 0.0; + } + + /** + * @description [获取CPU系统使用率] + * @author Leocoder + */ + public double getSysUsage() { + if (total > 0) { + return multiply(divide(sys, total, 4), 100); + } + return 0.0; + } + + /** + * @description [获取CPU用户使用率] + * @author Leocoder + */ + public double getUserUsage() { + if (total > 0) { + return multiply(divide(used, total, 4), 100); + } + return 0.0; + } + + /** + * @description [获取CPU等待率] + * @author Leocoder + */ + public double getWaitUsage() { + if (total > 0) { + return multiply(divide(wait, total, 4), 100); + } + return 0.0; + } + + /** + * @description [获取CPU空闲率] + * @author Leocoder + */ + public double getFreeUsage() { + if (total > 0) { + return multiply(divide(free, total, 4), 100); + } + return 0.0; + } + + /** + * 精确的除法运算 + */ + private static double divide(double v1, double v2, int scale) { + if (scale < 0) { + throw new IllegalArgumentException("精确度不能小于0"); + } + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); + } + + /** + * 精确的乘法运算 + */ + private static double multiply(double v1, double v2) { + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.multiply(b2).doubleValue(); + } +} \ No newline at end of file diff --git a/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Jvm.java b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Jvm.java new file mode 100644 index 0000000..8e437e2 --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Jvm.java @@ -0,0 +1,155 @@ +package org.leocoder.thin.monitor.pojo.server; + +import lombok.Data; + +import java.lang.management.ManagementFactory; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Date; + +/** + * @author Leocoder + * @description [JVM相关信息] + */ +@Data +public class Jvm { + + /** + * 当前JVM占用的内存总数(M) + */ + private long total; + + /** + * JVM最大可用内存总数(M) + */ + private long max; + + /** + * JVM空闲内存(M) + */ + private long free; + + /** + * JDK版本 + */ + private String version; + + /** + * JDK路径 + */ + private String home; + + /** + * @description [获取JVM已用内存] + * @author Leocoder + */ + public long getUsed() { + return total - free; + } + + /** + * @description [获取JVM内存使用率] + * @author Leocoder + */ + public double getUsage() { + if (total > 0) { + return multiply(divide(getUsed(), total, 4), 100); + } + return 0.0; + } + + /** + * @description [获取总内存(格式化)] + * @author Leocoder + */ + public String getTotalStr() { + return convertFileSize(total); + } + + /** + * @description [获取已用内存(格式化)] + * @author Leocoder + */ + public String getUsedStr() { + return convertFileSize(getUsed()); + } + + /** + * @description [获取剩余内存(格式化)] + * @author Leocoder + */ + public String getFreeStr() { + return convertFileSize(free); + } + + /** + * @description [获取最大内存(格式化)] + * @author Leocoder + */ + public String getMaxStr() { + return convertFileSize(max); + } + + /** + * @description [获取JVM启动时间] + * @author Leocoder + */ + public String getStartTime() { + long startTime = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new Date(startTime).toString(); + } + + /** + * @description [获取JVM运行时间] + * @author Leocoder + */ + public String getRunTime() { + long runTime = ManagementFactory.getRuntimeMXBean().getUptime(); + long day = runTime / (24 * 60 * 60 * 1000); + long hour = (runTime / (60 * 60 * 1000)) - (day * 24); + long minute = (runTime / (60 * 1000)) - (day * 24 * 60) - (hour * 60); + long second = (runTime / 1000) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60); + return String.format("%d天%d小时%d分钟%d秒", day, hour, minute, second); + } + + /** + * 字节转换 + */ + private String convertFileSize(long size) { + long kb = 1024; + long mb = kb * 1024; + long gb = mb * 1024; + if (size >= gb) { + return String.format("%.1f GB", (float) size / gb); + } else if (size >= mb) { + float f = (float) size / mb; + return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f); + } else if (size >= kb) { + float f = (float) size / kb; + return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f); + } else { + return String.format("%d B", size); + } + } + + /** + * 精确的除法运算 + */ + private static double divide(long v1, long v2, int scale) { + if (scale < 0) { + throw new IllegalArgumentException("精确度不能小于0"); + } + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); + } + + /** + * 精确的乘法运算 + */ + private static double multiply(double v1, double v2) { + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.multiply(b2).doubleValue(); + } +} \ No newline at end of file diff --git a/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Mem.java b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Mem.java new file mode 100644 index 0000000..8652fb2 --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Mem.java @@ -0,0 +1,105 @@ +package org.leocoder.thin.monitor.pojo.server; + +import lombok.Data; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * @author Leocoder + * @description [内存相关信息] + */ +@Data +public class Mem { + + /** + * 内存总量 + */ + private long total; + + /** + * 已用内存 + */ + private long used; + + /** + * 剩余内存 + */ + private long free; + + /** + * @description [获取内存使用率] + * @author Leocoder + */ + public double getUsage() { + if (total > 0) { + return multiply(divide(used, total, 4), 100); + } + return 0.0; + } + + /** + * @description [获取总内存(格式化)] + * @author Leocoder + */ + public String getTotalStr() { + return convertFileSize(total); + } + + /** + * @description [获取已用内存(格式化)] + * @author Leocoder + */ + public String getUsedStr() { + return convertFileSize(used); + } + + /** + * @description [获取剩余内存(格式化)] + * @author Leocoder + */ + public String getFreeStr() { + return convertFileSize(free); + } + + /** + * 字节转换 + */ + private String convertFileSize(long size) { + long kb = 1024; + long mb = kb * 1024; + long gb = mb * 1024; + if (size >= gb) { + return String.format("%.1f GB", (float) size / gb); + } else if (size >= mb) { + float f = (float) size / mb; + return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f); + } else if (size >= kb) { + float f = (float) size / kb; + return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f); + } else { + return String.format("%d B", size); + } + } + + /** + * 精确的除法运算 + */ + private static double divide(long v1, long v2, int scale) { + if (scale < 0) { + throw new IllegalArgumentException("精确度不能小于0"); + } + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); + } + + /** + * 精确的乘法运算 + */ + private static double multiply(double v1, double v2) { + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.multiply(b2).doubleValue(); + } +} \ No newline at end of file diff --git a/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Server.java b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Server.java new file mode 100644 index 0000000..d0db8a6 --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Server.java @@ -0,0 +1,202 @@ +package org.leocoder.thin.monitor.pojo.server; + +import lombok.Data; +import org.leocoder.thin.common.utils.ip.IpUtil; +import oshi.SystemInfo; +import oshi.hardware.CentralProcessor; +import oshi.hardware.CentralProcessor.TickType; +import oshi.hardware.GlobalMemory; +import oshi.hardware.HardwareAbstractionLayer; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; +import oshi.util.Util; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; + +/** + * @author Leocoder + * @description [服务器相关信息] + */ +@Data +public class Server { + + private static final int OSHI_WAIT_SECOND = 1000; + + /** + * CPU相关信息 + */ + private Cpu cpu = new Cpu(); + + /** + * 内存相关信息 + */ + private Mem mem = new Mem(); + + /** + * JVM相关信息 + */ + private Jvm jvm = new Jvm(); + + /** + * 服务器相关信息 + */ + private Sys sys = new Sys(); + + /** + * 磁盘相关信息 + */ + private List sysFiles = new LinkedList<>(); + + /** + * @description [获取服务器信息] + * @author Leocoder + */ + public void copyTo() { + try { + SystemInfo si = new SystemInfo(); + HardwareAbstractionLayer hal = si.getHardware(); + + setCpuInfo(hal.getProcessor()); + setMemInfo(hal.getMemory()); + setSysInfo(); + setJvmInfo(); + setSysFiles(si.getOperatingSystem()); + } catch (Exception e) { + System.err.println("获取服务器信息失败: " + e.getMessage()); + } + } + + /** + * 设置CPU信息 + */ + private void setCpuInfo(CentralProcessor processor) { + // CPU信息 + long[] prevTicks = processor.getSystemCpuLoadTicks(); + Util.sleep(OSHI_WAIT_SECOND); + long[] ticks = processor.getSystemCpuLoadTicks(); + long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()]; + long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()]; + long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()]; + long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()]; + long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()]; + long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()]; + long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()]; + long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()]; + long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal; + + cpu.setCpuNum(processor.getLogicalProcessorCount()); + cpu.setTotal(totalCpu); + cpu.setSys(cSys); + cpu.setUsed(user); + cpu.setWait(iowait); + cpu.setFree(idle); + } + + /** + * 设置内存信息 + */ + private void setMemInfo(GlobalMemory memory) { + mem.setTotal(memory.getTotal()); + mem.setUsed(memory.getTotal() - memory.getAvailable()); + mem.setFree(memory.getAvailable()); + } + + /** + * 设置服务器信息 + */ + private void setSysInfo() { + Properties props = System.getProperties(); + sys.setComputerName(IpUtil.getHostName()); + sys.setComputerIp(IpUtil.getHostIp()); + sys.setOsName(props.getProperty("os.name")); + sys.setOsArch(props.getProperty("os.arch")); + sys.setUserDir(props.getProperty("user.dir")); + } + + /** + * 设置Java虚拟机 + */ + private void setJvmInfo() { + Properties props = System.getProperties(); + jvm.setTotal(Runtime.getRuntime().totalMemory()); + jvm.setMax(Runtime.getRuntime().maxMemory()); + jvm.setFree(Runtime.getRuntime().freeMemory()); + jvm.setVersion(props.getProperty("java.version")); + jvm.setHome(props.getProperty("java.home")); + } + + /** + * 设置磁盘信息 + */ + private void setSysFiles(OperatingSystem os) { + FileSystem fileSystem = os.getFileSystem(); + List fsArray = fileSystem.getFileStores(); + for (OSFileStore fs : fsArray) { + long free = fs.getUsableSpace(); + long total = fs.getTotalSpace(); + long used = total - free; + SysFile sysFile = new SysFile(); + sysFile.setDirName(fs.getMount()); + sysFile.setSysTypeName(fs.getType()); + sysFile.setTypeName(fs.getName()); + sysFile.setTotal(convertFileSize(total)); + sysFile.setFree(convertFileSize(free)); + sysFile.setUsed(convertFileSize(used)); + if (total > 0) { + sysFile.setUsage(multiply(divide(used, total, 4), 100)); + } else { + sysFile.setUsage(0.0); + } + sysFiles.add(sysFile); + } + } + + /** + * 字节转换 + * + * @param size 字节大小 + * @return 转换后值 + */ + public String convertFileSize(long size) { + long kb = 1024; + long mb = kb * 1024; + long gb = mb * 1024; + if (size >= gb) { + return String.format("%.1f GB", (float) size / gb); + } else if (size >= mb) { + float f = (float) size / mb; + return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f); + } else if (size >= kb) { + float f = (float) size / kb; + return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f); + } else { + return String.format("%d B", size); + } + } + + /** + * 精确的除法运算 + */ + private static double divide(long v1, long v2, int scale) { + if (scale < 0) { + throw new IllegalArgumentException("精确度不能小于0"); + } + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); + } + + /** + * 精确的乘法运算 + */ + private static double multiply(double v1, double v2) { + BigDecimal b1 = BigDecimal.valueOf(v1); + BigDecimal b2 = BigDecimal.valueOf(v2); + return b1.multiply(b2).doubleValue(); + } +} \ No newline at end of file diff --git a/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Sys.java b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Sys.java new file mode 100644 index 0000000..9f70f27 --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/Sys.java @@ -0,0 +1,36 @@ +package org.leocoder.thin.monitor.pojo.server; + +import lombok.Data; + +/** + * @author Leocoder + * @description [系统相关信息] + */ +@Data +public class Sys { + + /** + * 服务器名称 + */ + private String computerName; + + /** + * 服务器IP + */ + private String computerIp; + + /** + * 项目路径 + */ + private String userDir; + + /** + * 操作系统 + */ + private String osName; + + /** + * 系统架构 + */ + private String osArch; +} \ No newline at end of file diff --git a/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/SysCache.java b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/SysCache.java new file mode 100644 index 0000000..72b373c --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/SysCache.java @@ -0,0 +1,52 @@ +package org.leocoder.thin.monitor.pojo.server; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; + +/** + * @author Leocoder + * @description [缓存信息] + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SysCache { + + /** + * 缓存名称 + */ + private String cacheName; + + /** + * 缓存键名 + */ + private String cacheKey; + + /** + * 缓存内容 + */ + private String cacheValue; + + /** + * 缓存过期时间 + */ + private String expireTime; + + /** + * 备注信息 + */ + private String remark; + + public SysCache(String cacheName, String remark) { + this.cacheName = cacheName; + this.remark = remark; + } + + public SysCache(String cacheName, String cacheKey, String cacheValue, String expireTime) { + this.cacheName = cacheName; + this.cacheKey = cacheKey; + this.cacheValue = cacheValue; + this.expireTime = expireTime; + } +} \ No newline at end of file diff --git a/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/SysFile.java b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/SysFile.java new file mode 100644 index 0000000..e189a66 --- /dev/null +++ b/coder-common-thin-modules/coder-common-thin-monitor/src/main/java/org/leocoder/thin/monitor/pojo/server/SysFile.java @@ -0,0 +1,46 @@ +package org.leocoder.thin.monitor.pojo.server; + +import lombok.Data; + +/** + * @author Leocoder + * @description [系统文件相关信息] + */ +@Data +public class SysFile { + + /** + * 盘符路径 + */ + private String dirName; + + /** + * 盘符类型 + */ + private String sysTypeName; + + /** + * 文件类型 + */ + private String typeName; + + /** + * 总大小 + */ + private String total; + + /** + * 剩余大小 + */ + private String free; + + /** + * 已经使用量 + */ + private String used; + + /** + * 资源的使用率 + */ + private double usage; +} \ No newline at end of file