基於 Linux /proc 虛擬文件系統採集指標,後端 Servlet 提供數據,前端 Ajax 輪詢渲染,支持 CPU、內存、溫度監控及業務異常告警。
public final class LinuxSystemTool {
/** 讀取 /proc/meminfo 解析內存信息
* @return int[4] = {MemTotal, MemFree, SwapTotal, SwapFree} (單位 KB) */
public static int[] getMemInfo() throws IOException, InterruptedException {
File file = new File("/proc/meminfo");
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
int[] result = new int[4];
String line;
while ((line = br.readLine()) != null) {
StringTokenizer st = new StringTokenizer(line);
if (!st.hasMoreTokens()) continue;
String key = st.nextToken();
if (!st.hasMoreTokens()) continue;
int val = Integer.parseInt(st.nextToken());
switch (key) {
case "MemTotal:": result[0] = val; break;
case "MemFree:": result[1] = val; break;
case "SwapTotal:": result[2] = val; break;
case "SwapFree:": result[3] = val; break;
}
}
return result;
}
}
/** 計算 CPU 使用率(採樣間隔 1 秒)
* @return 0.0~1.0 之間的浮點數 */
public static float getCpuInfo() throws IOException, InterruptedException {
File file = new File("/proc/stat");
long[] t1 = readCpuLine(file);
Thread.sleep(1000);
long[] t2 = readCpuLine(file);
long userDiff = t2[0] - t1[0];
long niceDiff = t2[1] - t1[1];
long sysDiff = t2[2] - t1[2];
long idleDiff = t2[3] - t1[3];
long totalDiff = userDiff + niceDiff + sysDiff + idleDiff;
return (float)(userDiff + niceDiff + sysDiff) / totalDiff;
}
private static long[] readCpuLine(File file) throws IOException {
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
StringTokenizer st = new StringTokenizer(br.readLine());
st.nextToken(); // 跳過 "cpu"
return new long[]{
Long.parseLong(st.nextToken()), // user
Long.parseLong(st.nextToken()), // nice
Long.parseLong(st.nextToken()), // sys
Long.parseLong(st.nextToken()) // idle
};
}
}
/** 讀取 CPU 溫度(需內核支持 thermal_zone) */
public static int getCpuTemp() throws IOException {
File file = new File("/proc/acpi/thermal_zone/THM/temperature");
if (!file.exists()) return -1; // 不支持
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
String line = br.readLine(); // 格式: "temperature: 68 C"
return Integer.parseInt(line.split(":")[1].trim().replace("C", ""));
}
}
}
CREATE TABLE warnlist (
Id BIGINT PRIMARY KEY AUTO_INCREMENT,
warnleave TINYINT DEFAULT 0, -- 0:企業級 1:運營商級
fromguy VARCHAR(20) NOT NULL, -- 告警來源用戶/組織
warncontent VARCHAR(100) NOT NULL, -- 告警內容
aviliablevalue VARCHAR(12), -- 閾值
warnvalue VARCHAR(12), -- 實際值
warntime DATETIME NOT NULL, -- 告警時間
stackinfo VARCHAR(255), -- 異常堆棧
dealwith TINYINT DEFAULT 0, -- 0:未處理 1:已處理
organizerID VARCHAR(20), -- 組織ID
des VARCHAR(255) -- 描述
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
// 伪代碼:每分鐘執行
if (cpuTemp > 75 || cpuUsage > 0.8) {
insertWarn("系統", "CPU溫度/使用率過高", "75/80%", String.valueOf(cpuTemp));
}
if (diskUsage > 0.9) {
insertWarn("系統", "磁盤空間不足", "90%", String.valueOf(diskUsage));
}
// 業務異常捕獲點統一調用
catch (Exception e) {
insertWarn(user, "業務異常", "", "", e.getStackTraceAsString());
}
避免時間戳不準導致漏報/重複:
MAX(Id) 存入 SessionlastMaxId,後端查 WHERE Id > ?<response>
<cpuUsed>67</cpuUsed>
<cpuTemp>76</cpuTemp>
<totalMemory>1023422</totalMemory>
<freeMemory>43244</freeMemory>
<warnlist>
<warnid>2</warnid>
<warncontent>系統存儲空間不足</warncontent>
<fromguy>kakaluyi</fromguy>
...
</warnlist>
<warnlist>...</warnlist>
</response>
var warns = req.responseXML.getElementsByTagName('warnlist');
var table = document.getElementById('warntable');
var tbody = table.tBodies[0];
var currentRows = tbody.rows.length;
// 刪除超出 50 條的舊行
if (currentRows + warns.length > 50) {
var removeCount = currentRows + warns.length - 50;
for (var i = 0; i < removeCount; i++) {
tbody.deleteRow(1); // 保留表頭第0行
}
}
// 追加新行
for (var i = 0; i < warns.length; i++) {
var w = warns[i];
var row = tbody.insertRow(-1);
row.style.backgroundColor = (totalRows++ % 2) ? "#BFD3F9" : "#FBFCEB";
var cells = [
totalRows,
w.getElementsByTagName('warnleave')[0].textContent == '0' ? '企業級告警' : '運營商級告警',
w.getElementsByTagName('fromguy')[0].textContent,
w.getElementsByTagName('warncontent')[0].textContent,
w.getElementsByTagName('aviliablevalue')[0].textContent,
'' + w.getElementsByTagName('warnvalue')[0].textContent + '',
w.getElementsByTagName('warntime')[0].textContent,
w.getElementsByTagName('dealwith')[0].textContent == '0' ? '未處理' : '已處理',
w.getElementsByTagName('warnid')[0].textContent
];
cells.forEach((text, idx) => {
var cell = row.insertCell(idx);
cell.className = 'listText';
cell.innerHTML = text;
});
}
(user+nice+sys)_diff / total_diffdeleteRow/insertRow 原生操作此架構可輕鬆擴展至多服務器集群監控,只需在採集端部署 Agent 並上報中心庫。