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