增加主机信息功能

This commit is contained in:
2026-04-18 11:07:29 +08:00
parent dbef9c7a06
commit 1821d266af

View File

@@ -0,0 +1,220 @@
package com.jeesite.modules.utils;
import com.jcraft.jsch.*;
import com.jeesite.modules.apps.Module.SftpResult;
import com.jeesite.modules.biz.entity.MySftpAccounts;
import io.micrometer.common.util.StringUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* 远程主机系统监控工具类
* 通过 SSH exec 采集 CPU、内存、磁盘、负载、在线时长等指标
*
* @author gaoxq
*/
public class MonitorUtil {
private static final int SSH_TIMEOUT = 5000;
// ------------------------------------------------------------------ 主入口
/**
* 采集远程主机系统信息
*
* @param account SSH账号复用 MySftpAccounts 的连接信息)
* @return MonitorResult
*/
public static SftpResult monitor(MySftpAccounts account) {
Session session = null;
ChannelExec exec = null;
try {
session = openSession(account);
exec = (ChannelExec) session.openChannel("exec");
exec.setCommand(buildScript());
InputStream in = exec.getInputStream();
InputStream errIn = exec.getErrStream();
exec.connect(SSH_TIMEOUT);
String output = readStream(in);
String err = readStream(errIn);
if (!err.isEmpty() && output.isEmpty()) {
return SftpResult.fail("采集失败: " + err);
}
return SftpResult.ok("采集成功", parse(output));
} catch (Exception e) {
return SftpResult.fail("采集失败: " + e.getMessage());
} finally {
if (exec != null && exec.isConnected()) exec.disconnect();
if (session != null && session.isConnected()) session.disconnect();
}
}
// ------------------------------------------------------------------ 采集脚本
private static String buildScript() {
return "echo '==MARK_HOSTNAME==' && hostname && " +
"echo '==MARK_OS==' && uname -o 2>/dev/null || echo Linux && " +
"echo '==MARK_UPTIME==' && uptime -p 2>/dev/null || uptime && " +
"echo '==MARK_CPU==' && top -bn1 | head -5 && " +
"echo '==MARK_MEM==' && free -m && " +
"echo '==MARK_DISK==' && df -h";
}
private static Map<String, Object> parse(String output) {
Map<String, Object> info = new LinkedHashMap<>();
info.put("hostname", extract(output, "MARK_HOSTNAME", true));
info.put("os", extract(output, "MARK_OS", true));
info.put("uptime", extract(output, "MARK_UPTIME", true));
info.put("cpu", parseCpu(extract(output, "MARK_CPU", false)));
info.put("memory", parseMemory(extract(output, "MARK_MEM", false)));
info.put("disk", parseDisk(extract(output, "MARK_DISK", false)));
return info;
}
// ---- CPU ----
/**
* 解析 top -bn1 输出
* Cpu(s): 1.2 us, 0.3 sy, 0.0 ni, 98.3 id, 0.1 wa, 0.1 si
*/
private static Map<String, String> parseCpu(String block) {
Map<String, String> cpu = new LinkedHashMap<>();
for (String line : block.split("\n")) {
if (line.startsWith("Cpu") || line.startsWith("%Cpu")) {
String data = line.replaceFirst(".*?:\\s*", "").replaceFirst("^%Cpu\\(s?\\):\\s*", "");
for (String part : data.split(",")) {
part = part.trim();
String[] kv = part.split("\\s+", 2);
if (kv.length >= 2) {
cpu.put(kv[1].trim(), kv[0].trim());
}
}
break;
}
}
return cpu;
}
/**
* 解析 free -m 输出
* Mem: total used free shared buff/cache available
*/
private static Map<String, String> parseMemory(String block) {
Map<String, String> mem = new LinkedHashMap<>();
for (String line : block.split("\n")) {
if (line.startsWith("Mem:")) {
String[] cols = line.trim().split("\\s+");
if (cols.length >= 7) {
mem.put("total", cols[1] + " MB");
mem.put("used", cols[2] + " MB");
mem.put("free", cols[3] + " MB");
mem.put("available", cols[6] + " MB");
try {
double total = Double.parseDouble(cols[1]);
double used = Double.parseDouble(cols[2]);
double pct = total > 0 ? used / total * 100 : 0;
mem.put("usagePercent", String.format("%.1f%%", pct));
} catch (NumberFormatException ignored) {
}
}
break;
}
}
return mem;
}
// ---- 磁盘 ----
/**
* 解析 df -h 输出
* Filesystem Size Used Avail Use% Mounted on
*/
private static List<Map<String, String>> parseDisk(String block) {
List<Map<String, String>> disks = new ArrayList<>();
String[] lines = block.split("\n");
for (int i = 0; i < lines.length; i++) {
String line = lines[i].trim();
if (i == 0 && (line.startsWith("Filesystem") || line.startsWith("文件系统"))) continue;
if (line.isEmpty()) continue;
String[] cols = line.split("\\s+");
if (cols.length >= 6) {
Map<String, String> d = new LinkedHashMap<>();
d.put("filesystem", cols[0]);
d.put("size", cols[1]);
d.put("used", cols[2]);
d.put("avail", cols[3]);
d.put("usePercent", cols[4]);
d.put("mounted", cols[5]);
disks.add(d);
}
}
return disks;
}
// ---- 段落提取 ----
private static String extract(String output, String mark, boolean singleLine) {
String start = "==" + mark + "==";
int s = output.indexOf(start);
if (s < 0) return "";
s += start.length();
if (s >= output.length()) return "";
if (output.charAt(s) == '\n') s++;
if (singleLine) {
int e = output.indexOf('\n', s);
return (e < 0 ? output.substring(s) : output.substring(s, e)).trim();
}
int e = output.indexOf("\n==", s);
return (e < 0 ? output.substring(s) : output.substring(s, e)).trim();
}
private static Session openSession(MySftpAccounts account) throws JSchException {
JSch jsch = new JSch();
int port = Optional.ofNullable(account.getHostPort()).orElse(22);
if ("key".equalsIgnoreCase(account.getAuthType())
&& StringUtils.isNotBlank(account.getPrivateKey())) {
jsch.addIdentity("tempKey",
account.getPrivateKey().getBytes(StandardCharsets.UTF_8),
null, null);
}
Session session = jsch.getSession(account.getUsername(), account.getHostIp(), port);
session.setTimeout(SSH_TIMEOUT);
if (!"key".equalsIgnoreCase(account.getAuthType())) {
session.setPassword(account.getPassword());
}
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect(SSH_TIMEOUT);
return session;
}
private static String readStream(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int len;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
return out.toString(StandardCharsets.UTF_8);
}
public static void main(String[] args) {
MySftpAccounts sftpAccounts = new MySftpAccounts();
sftpAccounts.setHostIp("192.168.31.194");
sftpAccounts.setHostPort(22);
sftpAccounts.setUsername("ogsapp");
sftpAccounts.setPassword("Sys@2026#me");
sftpAccounts.setRootPath("/ogsapp");
sftpAccounts.setAuthType("password");
SftpResult sftpResult = MonitorUtil.monitor(sftpAccounts);
System.out.println(sftpResult.getData());
}
}