用 WebSocket + Java 原生功能实现 Web 实时日志(兼容Win平台)

Tomcat 产生的日志以文件形式保存在服务器上。如果要在 Web 上浏览这些日志,采用 WebSocket + tail 命令是简单可行的方式,例如这文章介绍得都很好。只是在 Win 系统上面就没有类似 tail 命令行的工具,除非找第三方或者 PowerShell 的,多少有点不便,——尽管多数 Win 用于开发环境,日志直接在 IDE 控制台上看就可以了。这里为大家介绍的是一种原生 Java 方法浏览日志,实际上不复杂。

LogFileTailer

以下这个 LogFileTailer 类便是是实现 Linux tail 的跟踪日志功能,可持续监控某日志信息。tail 命令用途是依照要求将指定的文件的最后部分输出到标准设备,通常是终端,通俗讲来就是把某个档案文件的最后几行显示到终端上,假设该档案有更新,tail 会自己主动刷新,确保你看到最新的文件内容。

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.function.Consumer;

public class LogFileTailer extends Thread {
	private long sampleInterval = 2000;

	private File logfile;

	private boolean startAtBeginning;

	private Consumer<String> callback;

	/**
	 * 监视开关,true = 打开监视
	 */
	private boolean tailing;

	/**
	 * 
	 * @param file             要监视的文本文件
	 * @param sampleInterval   读取时间间隔
	 * @param startAtBeginning 是否显示文件头?还是说只显示后面变化的部分
	 */
	public LogFileTailer(String file, long sampleInterval, boolean startAtBeginning) {
		logfile = new File(file);
		this.sampleInterval = sampleInterval;
		this.startAtBeginning = startAtBeginning;
	}

	/**
	 * 设置回调事件
	 * 
	 * @param callback 回调事件
	 */
	public void addListener(Consumer<String> callback) {
		this.callback = callback;
	}

	/**
	 * 监视开关,true = 打开监视
	 * 
	 * @param tailing true = 打开监视
	 */
	public void setTailing(boolean tailing) {
		this.tailing = tailing;
	}

	@Override
	public void run() {
		long filePointer = startAtBeginning ? 0 : logfile.length();

		try {
			RandomAccessFile file = new RandomAccessFile(logfile, "r");
			while (tailing) {
				long fileLength = logfile.length();

				if (fileLength < filePointer) {
					file = new RandomAccessFile(logfile, "r");
					filePointer = 0;
				}

				if (fileLength > filePointer) {
					file.seek(filePointer);
					String line = file.readLine();

					while (line != null) {
						line = new String(line.getBytes("ISO-8859-1"), "utf-8");

						if (callback != null)
							callback.accept(line);
						line = file.readLine();
					}

					filePointer = file.getFilePointer();
				}

				sleep(sampleInterval);
			}

			file.close();
		} catch (IOException | InterruptedException e) {

		}
	}
}

测试代码如下。使用了 Java 8 的 Lambda 转入回调事件。

public static void main(String[] args) throws IOException {
		LogFileTailer tailer = new LogFileTailer("C:\\temp\\bar.txt", 1000, true);
		tailer.setTailing(true);
		tailer.addListener(System.out::println);
		tailer.start();
}

效果图如下
在这里插入图片描述

WebSocket

WebSocket 部分也比较简单,用户可以根据此自己扩展一下。


import java.io.IOException;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import com.ajaxjs.framework.BaseController;
import com.ajaxjs.mvc.controller.IController;
import com.ajaxjs.util.logger.LogHelper;

@ServerEndpoint("/tomcat_log")
@Path("/admin/tomcat-log")
public class TomcatLogController implements IController {
	private static final LogHelper LOGGER = LogHelper.getLog(TomcatLogController.class);

	private LogFileTailer tailer;

	@GET
	public String UI() {
		LOGGER.info("实时浏览 Tomcat 日志");
		return BaseController.jsp("admin/tomcat-log");
	}

	/**
	 * 新的WebSocket请求开启
	 */
	@OnOpen
	public void onOpen(Session session) {
		tailer = new LogFileTailer("C:\\temp\\bar.txt", 1000, true);
		tailer.setTailing(true);
		tailer.addListener(log -> {
			try {
				session.getBasicRemote().sendText(log + "<br />");
			} catch (IOException e) {
				LOGGER.warning(e);
			}
		});
		tailer.start();
	}

	/**
	 * WebSocket请求关闭
	 */
	@OnClose
	public void onClose() {
		tailer.setTailing(false);
	}

	@OnError
	public void onError(Throwable thr) {
		thr.printStackTrace();
	}
}

前端

<div id="log-container" style="height: 450px; overflow-y: scroll; background: #333; color: #aaa; padding: 10px; margin: 0 auto;width: 89%;">
	<div></div>
</div>

<script src="//cdn.bootcss.com/jquery/2.1.4/jquery.js"></script>
<script>
	$(document).ready(function() {
		// 指定websocket路径
		var websocket = new WebSocket('ws://' + document.location.host + '/${ctx}/tomcat_log');
		websocket.onmessage = function(event) {
			// 接收服务端的实时日志并添加到HTML页面中
			$("#log-container div").append(event.data);
			// 滚动条滚动到最低部
			$("#log-container").scrollTop($("#log-container div").height() - $("#log-container").height());
		};
	});
</script>

参考

  • https://blog.51cto.com/6140717/1052845
  • https://www.cnblogs.com/snowater/p/7603611.html
  • https://blog.csdn.net/xxgwo/article/details/51198113
©️2020 CSDN 皮肤主题: 岁月 设计师:pinMode 返回首页