需求

通过java接口实现简单的linux系统实时监控,
希望尽可能不增加系统算力和内存负担的基础上,
获取到系统信息,方便前端用图表来显示系统情况



代码实现

说明:为减少查询本身带来的消耗,基本用java和linux原生语法,没用第三方依赖,代码中的唯一依赖的StringUtils,只是做非空判断
例如

  1. if (StringUtils.isNotBlank(string)) {
  2. }
  3. // 等价于
  4. if (string != null && !"".equals(string)) {
  5. }

LinuxUtils.java

  1. import org.apache.commons.lang.StringUtils;
  2. import java.io.*;
  3. import java.util.ArrayList;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.Map;
  7. public class LinuxUtils {
  8. /**
  9. * java执行linux命令
  10. */
  11. public String exec(String cmd) {
  12. try {
  13. String[] cmdA = {"/bin/sh", "-c", cmd};
  14. Process process = Runtime.getRuntime().exec(cmdA);
  15. LineNumberReader br = new LineNumberReader(new InputStreamReader(
  16. process.getInputStream()));
  17. StringBuffer sb = new StringBuffer();
  18. String line;
  19. while ((line = br.readLine()) != null) {
  20. sb.append(line).append("\n");
  21. }
  22. return sb.toString();
  23. } catch (Exception e) {
  24. e.printStackTrace();
  25. }
  26. return null;
  27. }
  28. /**
  29. * 格式化linux返回
  30. * 返回一个二维数组
  31. */
  32. public List<List<String>> format(String string) {
  33. List<List<String>> result = new ArrayList<>();
  34. if (StringUtils.isNotBlank(string)) {
  35. String[] lines = string.split("\n");
  36. for (String line : lines) {
  37. String[] strings = line.split(" ");
  38. List<String> temp = new ArrayList<>();
  39. for (String str : strings) {
  40. if (StringUtils.isNotBlank(str)) {
  41. temp.add(str);
  42. }
  43. }
  44. result.add(temp);
  45. }
  46. }
  47. return result;
  48. }
  49. /**
  50. * 获取linux下 系统盘使用情况
  51. */
  52. public Map<String, Object> getDeskInfo() {
  53. Map<String, Object> result = new HashMap<>();
  54. try {
  55. String info = exec("df");
  56. List<List<String>> lists = format(info);
  57. for (List<String> list : lists) {
  58. if (list.size() >= 6 && "/".equals(list.get(5))) {
  59. for (int i = 0; i < list.size(); i++) {
  60. // 文件系统名称
  61. result.put("diskName", list.get(0));
  62. // 总空间
  63. result.put("total", list.get(1));
  64. // 已用
  65. result.put("used", list.get(2));
  66. // 可用
  67. result.put("free", list.get(3));
  68. // 百分比
  69. result.put("useRate", list.get(4));
  70. }
  71. }
  72. }
  73. } catch (Exception e) {
  74. e.printStackTrace();
  75. }
  76. return result;
  77. }
  78. /**
  79. * 获取linux下 内存使用情况
  80. * mem 为内存
  81. * swap为交换区
  82. */
  83. public Map<String, Object> getRamInfo() {
  84. Map<String, Object> result = new HashMap<>();
  85. try {
  86. String info = exec("free");
  87. List<List<String>> lists = format(info);
  88. for (List<String> list : lists) {
  89. if (StringUtils.isNotBlank(list.get(0)) && list.get(0).toLowerCase().contains("mem")) {
  90. Map<String, Object> mem = new HashMap<>();
  91. mem.put("total", list.get(1));
  92. mem.put("used", list.get(2));
  93. mem.put("free", list.get(3));
  94. mem.put("shared", list.get(4));
  95. mem.put("cache", list.get(5));
  96. mem.put("available", list.get(6));
  97. result.put("mem", mem);
  98. } else if (StringUtils.isNotBlank(list.get(0)) && list.get(0).toLowerCase().contains("swap")) {
  99. Map<String, Object> swap = new HashMap<>();
  100. swap.put("total", list.get(1));
  101. swap.put("used", list.get(2));
  102. swap.put("free", list.get(3));
  103. result.put("swap", swap);
  104. }
  105. }
  106. } catch (
  107. Exception e) {
  108. e.printStackTrace();
  109. }
  110. return result;
  111. }
  112. /**
  113. * 获取linux下 CPU使用情况 (使用top -b -n 1 实现,亲测不是十分准确,暂未使用)
  114. */
  115. public Map<String, Object> getCPUInfoByTop() {
  116. Map<String, Object> result = new HashMap<>();
  117. try {
  118. String info = exec("top -b -n 1 | sed -n '3p'");
  119. String[] strings = info.split(":")[1].split(",");
  120. for (String string : strings) {
  121. if (StringUtils.isNotBlank(string) && string.toLowerCase().contains("id")) {
  122. String free = string.replace("id", "").trim();
  123. result.put("free", free);
  124. String used = String.valueOf((10000 - Double.parseDouble(free) * 100) / 100);
  125. result.put("used", used);
  126. }
  127. }
  128. } catch (
  129. Exception e) {
  130. e.printStackTrace();
  131. }
  132. return result;
  133. }
  134. /**
  135. * 获取linux下 CPU使用情况 通过采集两次/proc/stat 计算CPU差值对比实现
  136. * 参考:
  137. * https://www.cnblogs.com/shihaiming/p/7048264.html
  138. * https://www.cnblogs.com/gisblogs/p/3985393.html
  139. */
  140. public Map<String, Object> getCPUInfo() {
  141. Map<String, Object> result = new HashMap<>();
  142. try {
  143. String info = exec("cat /proc/stat");
  144. List<String> cpu1 = format(info).get(0);
  145. // 间隔时间 推荐设置在 200 - 5000 毫秒之间 (小了不准 大了太慢)
  146. Thread.sleep(200);
  147. info = exec("cat /proc/stat");
  148. List<String> cpu2 = format(info).get(0);
  149. // 用初中数学优化了一下网上的算法
  150. float total = Float.parseFloat(cpu2.get(1)) - Float.parseFloat(cpu1.get(1)) +
  151. Float.parseFloat(cpu2.get(2)) - Float.parseFloat(cpu1.get(2)) +
  152. Float.parseFloat(cpu2.get(3)) - Float.parseFloat(cpu1.get(3));
  153. float totalidle = total + Float.parseFloat(cpu2.get(4)) - Float.parseFloat(cpu1.get(4));
  154. float useRate = (total / totalidle) * 100;
  155. result.put("useRate", useRate);
  156. } catch (
  157. Exception e) {
  158. e.printStackTrace();
  159. }
  160. return result;
  161. }
  162. public static void main(String[] args) {
  163. long time = System.currentTimeMillis();
  164. LinuxUtils linuxUtils = new LinuxUtils();
  165. System.out.println(linuxUtils.getDeskInfo());
  166. System.out.println(linuxUtils.getRamInfo());
  167. System.out.println(linuxUtils.getCPUInfo());
  168. System.out.println("消耗时间:" + (System.currentTimeMillis() - time) / 1000.0 + "秒");
  169. }
  170. }


运行结果

  1. {diskName=/dev/nvme0n1p5, total=105306896, used=44633952, useRate=45%, free=55280560}
  2. {mem={shared=120712, total=3950000, cache=639268, available=809536, used=2774656, free=536076}, swap={total=8388604, used=3328976, free=5059628}}
  3. {useRate=70.0}
  4. 消耗时间:0.277