今天想和大家聊聊一个非常实用的项目——实时日志监控可视化平台。想必每个开发者在开发过程中都遇到过“日志查看”这个头痛问题吧?尤其是在复杂的生产环境中,日志量巨大,往往难以在海量信息中找到真正的根源。
这个时候,有一个清晰、实时、自动化的日志监控平台就显得尤为重要。
1. 前言
日志,对于开发者来说,不仅是调试的重要工具,更是我们排查故障、追踪问题的关键。在很多情况下,尤其是我们将应用部署到生产环境后,系统异常、错误信息、业务请求等都会被记录在日志中,而这些信息往往就是排查问题的线索。
可是,大家有没有遇到过这样的情况?系统出现问题时,日志文件大到让你头痛不已,根本不知道从哪里入手查看。尤其是需要通过远程连接到服务器,手动下载日志,甚至通过grep
或tail
等命令在几百行甚至几千行日志中苦苦寻找,那种“有了问题才想到日志”的场景真的是让人既崩溃又心累。
为了减少这种痛苦,我做了一个小项目——实时日志监控可视化平台。它基于SpringBoot和Vue的技术栈,通过WebSocket将后端日志实时推送到前端,帮助我们随时掌握系统的运行状况,快速定位问题,简化了很多繁琐的操作。
2. 需求分析
需求目标:
我们需要一个实时获取系统日志并将其展示到前端的服务,主要目的是帮助开发者和运维人员更方便地查看日志、定位问题。对于前端,我们需要一个简洁易用的界面,能够实时显示日志并根据日志级别(如DEBUG、WARN、ERROR等)进行高亮区分。对于后台,SpringBoot将作为服务端,处理日志捕获与推送,Vue3则用来显示这些信息。
技术栈:
后端:SpringBoot + Logback + WebSocket 前端:Vue3 + WebSocket
我之所以选用SpringBoot,是因为它是一个非常强大且简单的后台框架,能快速构建RESTful API、配置任务调度等。而Vue3则提供了灵活的视图组件,能够与WebSocket结合,实时展示日志信息。
3. 前端部分实现:Vue3 + WebSocket
核心代码:
在前端部分,我们使用了Vue3来构建UI,并通过WebSocket实现日志的实时推送。以下是我实现的一个简单示例代码:
<template>
<div class="log-container">
<div v-for="log in logs" :key="log.id" :class="log.level">
<span>{{ log.timestamp }}</span>
<span>{{ log.message }}</span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
logs: [],
socket: null
};
},
mounted() {
this.connect();
},
methods: {
// 连接WebSocket
connect() {
this.socket = new WebSocket("ws://localhost:8080/logs");
this.socket.onopen = () => {
console.log("WebSocket连接成功!");
};
this.socket.onmessage = this.onMessage;
this.socket.onerror = (error) => {
console.log("WebSocket错误:", error);
};
},
// 处理WebSocket消息
onMessage(event) {
const log = JSON.parse(event.data);
this.logs.push(log);
}
}
};
</script>
<style scoped>
.log-container {
max-height: 300px;
overflow-y: scroll;
}
.DEBUG { color: gray; }
.WARN { color: orange; }
.ERROR { color: red; }
</style>
上面的代码展示了如何使用Vue3连接WebSocket,并将接收到的日志按不同级别(如DEBUG、WARN、ERROR)渲染到页面上。通过使用v-for
指令将日志按时间顺序展示,<span>
标签中显示日志的时间戳和具体内容。
如何处理WebSocket连接:
我们在mounted()
钩子中建立WebSocket连接,并在onmessage
事件中接收日志信息。每次接收到一条新日志,我们将其加入到logs
数组中,从而实现实时更新。
4. 后台部分实现:SpringBoot + WebSocket
日志拦截器配置:
在后台,我们使用了SpringBoot结合Logback来捕获系统日志,并通过WebSocket将日志实时推送到前端。
<configuration>
<appender name="webSocket" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="webSocket"/>
</root>
</configuration>
这个配置文件是Logback的标准配置,通过它我们可以捕获系统的日志并将其推送到WebSocket连接中。
LogFilter 实现:
为了更灵活地捕获日志并推送,我们自定义了一个LogFilter
,继承自Logback的Filter
类:
@Component
public class LogFilter extends Filter<ILoggingEvent> {
private final BlockingQueue<LogMessage> logQueue;
@Autowired
public LogFilter(BlockingQueue<LogMessage> logQueue) {
this.logQueue = logQueue;
}
@Override
public FilterReply decide(ILoggingEvent event) {
LogMessage logMessage = new LogMessage(event.getTimestamp(), event.getLevel().toString(), event.getMessage());
logQueue.offer(logMessage); // 将日志推送到队列
return FilterReply.ACCEPT;
}
}
这个LogFilter
类捕获了所有日志信息,并将其放入一个非阻塞队列logQueue
中。接下来,我们使用WebSocket服务将日志推送到前端。
WebSocket服务器:
@ServerEndpoint("/logs")
@Component
public class LogWebSocketServer {
private static final ExecutorService executorService = Executors.newFixedThreadPool(10);
@Autowired
private BlockingQueue<LogMessage> logQueue;
@OnOpen
public void onOpen(Session session) {
executorService.submit(() -> {
while (true) {
try {
LogMessage log = logQueue.take(); // 获取日志
session.getBasicRemote().sendText(log.toJson()); // 发送到前端
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
}
});
}
}
这里,我们创建了一个WebSocket服务器,使用ExecutorService
异步地从日志队列中获取日志并推送给前端。这样做可以避免阻塞主线程,确保系统的响应速度。
5. 优化建议
虽然以上方案已经可以实现基本的实时日志展示,但如果系统的日志量过大,可能会对服务器性能造成压力。为了减少性能瓶颈,我们可以引入消息队列(如Kafka、RabbitMQ)来处理日志消息的转发,解耦日志收集与推送,避免日志产生高峰时对系统性能产生过大影响。
通过实现这个实时日志监控平台,我们不再需要手动去查找日志文件,也不必在海量日志中“找针”。
借助SpringBoot和Vue的结合,我们轻松实现了日志的实时展示,让问题排查变得更加高效。
大家如果对代码实现感兴趣,可以参考GitHub上的代码仓库:
https://github.com/bertguan96/zeus
好了,今天的分享就到这里👋
对编程、职场感兴趣的同学,可以链接我,微信:coder301 拉你进入“程序员交流群”。