當前位置: 妍妍網 > 碼農

SpringBoot+Vue 實作了一個日誌監控視覺化平台

2024-05-23碼農

點選關註公眾號,Java幹貨 及時送達 👇

日誌服務是作為軟體開發架構的必備服務之一,一直都是我們所關註,所考慮的服務關鍵點,一個優秀的日誌服務可以為計畫的維護提供有力的支持,提高了系統的可靠性。

前言

如何設計一個優秀而又可靠的日誌服務,是一直以來都是一個很難的課題,寫本文的目的起源於大學時期做的一個計畫,那時候後台部署到阿裏雲上,每次遇到Error的問題的時候都需要登陸伺服器檢視,非常的麻煩,於是我就突發奇想為什麽不對Spring的日誌進行攔截,展示到前端界面呢?於是就產生了這個計畫。

開工

在開始之前,我們需要捋清楚,我們的需求是什麽?透過思考,我們得知,我們的需求是能夠即時獲取系統輸出日誌,並展示到我們的前端,用於運維和問題排查。

在明確了目的之後,我們可以開始了開發工作,首先是技術選型,我們所選擇的是SpringBoot + Vue來搭配。鑒於寫文本的時候Vue3已經釋出了,所以才用的是最新的Vue3來進行開發。

程式碼部份

前端

前端所選用的通訊技術為:Vue3 + Websocket,日誌透過Websocket即時同步到前端,具體實作如下。

mounted() {
this.res = document.getElementById('terminal-console');
this.websocket = new WebSocket("ws://127.0.0.1:8080/websocket/logger");
this.renderConsole()
this.connect()
},

1.渲染程式碼架子。

2.建立Websocket連結。

3.渲染控制台

4.建立連結,開始接收日誌,這裏由於前端篇幅問題,我就直接放核心程式碼了,後續如果需要進一步的可以前往github進行下載。

connect() {
this.res.appendChild(this.createDivElement('通道連線成功,靜默等待....'))
const _this = this;
if (this.websocket != null) {
this.websocket.open = function () {
this.websocket.send("數據發送");
};
this.websocket.onmessage = function (event) {
// 處理日誌
const content = JSON.parse(event.data);
let levelHtml = _this.createSpanElement(content.level, '#90ad2b');
const className = _this.createSpanElement(content. className, '#229379')
switch (content.level) {
case'DEBUG':
levelHtml = _this.createSpanElement(content.level, '#A8C023');
break;
case'WARN':
levelHtml = _this.createSpanElement(content.level, '#fffa1c');
break;
case'ERROR':
levelHtml = _this.createSpanElement(content.level, '#e3270e');
break;
}
const logger = _this.createDivElement(content.timestamp)
logger.appendChild(levelHtml)
logger.innerHTML = logger.innerHTML + " --- [" + content.threadName + "] "
logger.appendChild( className)
logger.innerHTML = logger.innerHTML + " :" + content.body
_this.res.appendChild(logger)
}
}
}

後台

後台部份實作思路如下:

1.在logger.xml配置檔中配置日誌攔截器,同時實作攔截器類,下方的filter就是我們的實作的過濾器。

%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

2.緊接著就是實作過濾的能力,這塊就不用說了,就是實作了logger的過濾能力,其思路就是繼承logback的Filter,實作過濾方法,在過濾過程中提取關鍵字,並寫入佇列。

@Service
public class LogFilter extends Filter {
@Override
public FilterReply decide(ILoggingEvent event) {
String exception = "";
IThrowableProxy iThrowableProxy1 = event.getThrowableProxy();
if (iThrowableProxy1 != null) {
exception = "" + iThrowableProxy1.get className() + " " + iThrowableProxy1.getMessage() + "
"
;
for (int i = 0; i < iThrowableProxy1.getStackTraceElementProxyArray().length; i++) {
exception += "" + iThrowableProxy1.getStackTraceElementProxyArray()[i].toString() + "
"
;
}
}
 // 建立日誌訊息
LoggerMessage loggerMessage = new LoggerMessage(
event.getMessage()
, DateFormat.getDateTimeInstance().format(new Date(event.getTimeStamp())),
event.getThreadName(),
event.getLoggerName(),
event.getLevel().levelStr,
exception,
""
);
 // 寫入非阻塞佇列
LoggerQueue.getInstance().push(loggerMessage);
return FilterReply.ACCEPT;
}
}

3.寫入過後呢,就由websocket類,來即時提取返回給前端,核心程式碼如下,其實就是建立一個執行緒池,不停的去獲取佇列的內容,如果有的話就返回給前端,如果沒有就跳過(當然這樣實作很挫,最好呢是吧訊息丟進訊息佇列,然後有一個伺服端去異步消費個前端)。

public void send() {
ExecutorService executorService= Executors.newFixedThreadPool(2);
Runnable runnable= () -> {
while (true) {
try {
LoggerMessage log = LoggerQueue.getInstance().poll();
if(log!=null){
sendInfo(JSON.toJSONString(log), "logger");
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
executorService.submit(runnable);
}

結束

透過上面一頓操作,我們基本完成了,一個日誌服務的搭建過程,不過這裏還是有不足的,比如利用訊息佇列來中轉日誌訊息,這樣可以避免開執行緒給伺服器造成無關的壓力。

程式碼倉庫

https://github.com/bertguan96/zeus

來源:juejin.cn/post/7214068367607070781

END


看完本文有收獲?請轉發分享給更多人

關註「Java編程鴨」,提升Java技能

關註Java編程鴨微信公眾號,後台回復:碼農大禮包可以獲取最新整理的技術資料一份。涵蓋Java 框架學習、架構師學習等!

文章有幫助的話,在看,轉發吧。

謝謝支持喲 (*^__^*)