Java Web 简单监控

Posted sp42a

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java Web 简单监控相关的知识,希望对你有一定的参考价值。

原理就是获取信息,然后解析并转化为目标结构信息输出。

监控包括下面几个维度:

  • OS:CPU 利用率,CPU 温度,总内存大小,已使用内存大小
  • JVM
  • Tomcat
  • 你的应用程序,包括异常信息

如何获取系统信息

获取方式各种各样,可综合使用:

  • 系统的命令行,Java 用 runtime.exec() 函数获取之,或者封装一下 Shell 脚本
  • Linux 提供的系统信息,通过文件管道获取之,例如 $ cat /proc/meminfo
  • 对底层系统的调用和操作一般用 Java JNI 来完成,如 Sigar
  • Java 自带的方法,如 System 类以及 RuntimeRuntimeMXBean
  • oshi,偏向于硬件监控

系统的命令行

JM 是该方法的代表,主要是监控 JVM 的,作者是大牛

我找到一个 runtime.exec() 比较优秀的方法:

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * Create by yster@foxmail.com 2018/11/9 0009 22:28
 */
public class ExecuteCmd 
    /**
     * 执行外部程序,并获取标准输出
     */
    public static String execute(String[] cmd,String... encoding) 
        BufferedReader bufferedReader;
        InputStreamReader inputStreamReader;
        try 
            Process p = Runtime.getRuntime().exec(cmd);

            /* 为"错误输出流"单独开一个线程读取之,否则会造成标准输出流的阻塞 */
            Thread t = new Thread(new InputStreamRunnable(p.getErrorStream(), "ErrorStream"));
            t.start();

            /* "标准输出流"就在当前方法中读取 */
            BufferedInputStream bis = new BufferedInputStream(p.getInputStream());

            if (encoding != null && encoding.length != 0) 
                inputStreamReader = new InputStreamReader(bis, encoding[0]);// 设置编码方式
             else 
                inputStreamReader = new InputStreamReader(bis, "utf-8");
            
            bufferedReader = new BufferedReader(inputStreamReader);

            StringBuilder sb = new StringBuilder();
            String line;

            while ((line = bufferedReader.readLine()) != null) 
                sb.append(line);
                sb.append("\\n");
            

            bufferedReader.close();
            p.destroy();
            return sb.toString();
         catch (Exception e) 
            e.printStackTrace();
            return null;
        
    


Linux 提供的系统信息

获取 CPU 信息那个函数有点 Bug……这是代码出处:《JavaWeb 的监控系统》,说得不错。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * 
 * @author https://blog.csdn.net/hj7jay/article/details/51979939
 *
 */
public class LinuxSystemTool 
	/**
	 * 内存的信息
	 * 
	 * get memory by used info
	 * 
	 * @return int[] result
	 *         result.length==4;int[0]=MemTotal;int[1]=MemFree;int[2]=SwapTotal;int[3]=SwapFree;
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static int[] getMemInfo() throws IOException, InterruptedException 
		File file = new File("/proc/meminfo");
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
		int[] result = new int[4];
		String str = null;
		StringTokenizer token = null;
		while ((str = br.readLine()) != null) 
			token = new StringTokenizer(str);
			if (!token.hasMoreTokens())
				continue;

			str = token.nextToken();
			if (!token.hasMoreTokens())
				continue;

			if (str.equalsIgnoreCase("MemTotal:"))
				result[0] = Integer.parseInt(token.nextToken());
			else if (str.equalsIgnoreCase("MemFree:"))
				result[1] = Integer.parseInt(token.nextToken());
			else if (str.equalsIgnoreCase("SwapTotal:"))
				result[2] = Integer.parseInt(token.nextToken());
			else if (str.equalsIgnoreCase("SwapFree:"))
				result[3] = Integer.parseInt(token.nextToken());
		

		br.close();
		Arrays.toString(result);
		return result;
	

	/**
	 * get cpu by used info
	 * 
	 * @return float efficiency
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static float getCpuInfo() throws IOException, InterruptedException 
		File file = new File("/proc/stat");
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
		StringTokenizer token = new StringTokenizer(br.readLine());
		token.nextToken();
		int user1 = Integer.parseInt(token.nextToken());
		int nice1 = Integer.parseInt(token.nextToken());
		int sys1 = Integer.parseInt(token.nextToken());
		int idle1 = Integer.parseInt(token.nextToken());
		br.close();
		Thread.sleep(1000);

		br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
		token = new StringTokenizer(br.readLine());
		token.nextToken();
		int user2 = Integer.parseInt(token.nextToken());
		int nice2 = Integer.parseInt(token.nextToken());
		int sys2 = Integer.parseInt(token.nextToken());
		int idle2 = Integer.parseInt(token.nextToken());

		br.close();

		return (float) ((user2 + sys2 + nice2) - (user1 + sys1 + nice1)) / (float) ((user2 + nice2 + sys2 + idle2) - (user1 + nice1 + sys1 + idle1));
	

关于 Sigar

很多监控利用 Sigar 获取相关信息,例如 JeeSite 和这个开源项目 JMonitor 但是 Sigar 用起来比较麻烦:

Sigar有C,C#,Java和Perl API,java版的API为sigar.jar sigar.jar的底层是用C语言编写的,它通过本地方法来调用操作系统API来获取系统相关数据。Windows操作系统下Sigar.jar 依赖sigar-amd64-winnt.dll或sigar-x86-winnt.dll,linux 操作系统下则依赖libsigar-amd64-linux.so或libsigar-x86-linux.so

这篇文章中,作者比较详细地介绍 Sigar 的用法,再结合上述资源,使用 Sigar 问题不大。但是我并不打算基于 Sigar 来做。

Java 自带的方法

  • JVM 实时打印内存情况等,通过 ManagementFactory.getOperatingSystemMXBean()ManagementFactory.getRuntimeMXBean() 来实现监控
  • Thread监控,通过 ManagementFactory.getThreadMXBean() 来实现监控
  • GC 监控,通过 ManagementFactory.getGarbageCollectorMXBeans() 来实现监控

oshi (推荐)

相比 Sigar,oshi 不用自己添加依赖文件。

<dependency>
    <groupId>com.github.oshi</groupId>
    <artifactId>oshi-core</artifactId>
    <version>3.4.4</version>
</dependency>
  • https://www.cnblogs.com/sundaboke/p/8493937.html
  • https://blog.csdn.net/u012068483/article/details/104844143/
  • https://zhuanlan.zhihu.com/p/149013115
  • https://blog.csdn.net/weixin_43003720/article/details/111870418

其他高大上方法

  • CAT
  • Tomcat+Prometheus+Grafana
  • Java Melody

参考

以上是关于Java Web 简单监控的主要内容,如果未能解决你的问题,请参考以下文章

web项目实现后台监控

cacti监控windows简单笔记!

[原创]java WEB学习笔记12:一个简单的serlet连接数据库实验

[原创]java WEB学习笔记41:简单标签之带属性的自定义标签

Java监控本地日志并实现实时查看

Java监控本地日志并实现实时查看