重构 日志广播与历史记录

This commit is contained in:
Suwings 2020-03-09 15:26:00 +08:00
parent b479ec70b7
commit 2a7e73a2a3
4 changed files with 119 additions and 83 deletions

View File

@ -1,72 +1,90 @@
"use strict";
// 日志历史储存
const MAX_HISTORY_SIZE = 1000;
const DELETE_ALTER_INIT_SIZE = 600;
const fs = require('fs');
const fsExtra = require('fs-extra');
const MAX_HISTORY_SIZE = 1024 * 1024 * 1;
const BASE_RECORD_DIR = './server/tmp_log_history/';
const FILE_CODE = "utf8";
class LogHistory {
constructor(id) {
this.id = id;
this.readPoints = {};
this.log = new Array();
this.path = BASE_RECORD_DIR + id + '.log';
if (!fsExtra.existsSync(BASE_RECORD_DIR)) {
fsExtra.mkdirs(BASE_RECORD_DIR);
}
}
writeLine(text = "") {
if (text.length == 0) return;
if (this.log.length > MAX_HISTORY_SIZE) {
this.log.splice(0, DELETE_ALTER_INIT_SIZE);
}
let addLineLength = 0;
text = text.replace(/\r/igm, "");
if (text.indexOf('\n') != -1) {
let arr = text.split('\n');
for (let v of arr) {
if (v) {
this.log.push(v);
addLineLength++;
if (fs.existsSync(this.path))
fs.appendFile(this.path, text, FILE_CODE, (err) => {
if (err) MCSERVER.log('实例', this.id, '日志历史记录文件写入错误:', err.message);
let fsstat = fs.statSync(this.path);
let size = fsstat.size;
if (size > MAX_HISTORY_SIZE) {
fs.unlinkSync(this.path);
}
});
else
fs.writeFile(this.path, text, (err) => {
if (err) MCSERVER.log('实例', this.id, '日志历史记录文件创建错误:', err.message);
});
}
readLine(demander = "", size = 1024, callback = () => { }) {
if (!this.readPoints[demander]) {
this.readPoints[demander] = 0;
}
const demanderPoint = this.readPoints[demander];
const buffer = Buffer.alloc(size);
fs.open(this.path, 'r', (err, fd) => {
if (err) {
MCSERVER.log('实例', this.id, '日志历史记录文件打开错误:', err.message);
return;
}
} else {
this.log.push(text);
addLineLength++;
}
for (let k in this.readPoints) {
this.readPoints[k] += addLineLength;
}
fs.read(fd, buffer, 0, size, demanderPoint, (err, bytesRead, buffer) => {
if (err) {
MCSERVER.log('实例', this.id, '日志历史记录文件读取错误:', err.message);
return;
};
const logText = buffer.slice(0, bytesRead).toString();
this.readPoints[demander] += size;
callback && callback(logText);
// 关闭文件
fs.close(fd, () => { });
});
});
}
readLine(demander = "", size = 10) {
readLineReverse(demander = "", size = 1024, notadd = false, callback = () => { }) {
if (!this.readPoints[demander]) {
this.readPoints[demander] = 0;
}
let demanderPoint = this.readPoints[demander];
let text = "";
let logarr = this.log;
let i;
for (i = demanderPoint; i <= demanderPoint + size; i++) {
let point = logarr.length - i - 1;
if (point < 0) break;
let v = logarr[point] + '\n';
if (logarr[point] && logarr[point].trim().length > 0) text += v;
}
this.readPoints[demander] = demanderPoint + size;
return text;
}
readLineReverse(demander = "", size = 10, notadd = false) {
if (!this.readPoints[demander]) {
this.readPoints[demander] = 0;
}
let demanderPoint = this.readPoints[demander];
let text = "";
let logarr = this.log;
let i;
for (i = (logarr.length - 1 - size - demanderPoint); i < logarr.length - demanderPoint; i++) {
let v = logarr[i] + '\n';
if (logarr[i] && logarr[i].trim().length > 0) text += v;
}
const demanderPoint = this.readPoints[demander];
const buffer = Buffer.alloc(size);
fs.open(this.path, 'r', (err, fd) => {
if (err) {
MCSERVER.log('实例', this.id, '日志历史记录文件打开错误:', err.message);
return;
}
fs.read(fd, buffer, 0, size, demanderPoint, (err, bytesRead, buffer) => {
if (err) {
MCSERVER.log('实例', this.id, '日志历史记录文件读取错误:', err.message);
return;
};
const logText = buffer.slice(0, bytesRead).toString();
this.readPoints[demander] += size;
callback && callback(logText);
// 关闭文件
fs.close(fd, () => { });
});
});
if (!notadd) this.readPoints[demander] = demanderPoint + size;
return text;
}
setPoint(demander, v) {

View File

@ -96,7 +96,8 @@
<div class="PanelTitle">实时终端控制台</div>
<div class="PanelBody">
<!-- 终端 -->
<div id="WebTerminal" class="WebTerminalScreen"></div>
<div id="WebTerminal" class="WebTerminalScreen" style="display: block;"></div>
<div id="LogHistoryTerminal" class="WebTerminalScreen" style="display: block;"></div>
</div>
</div>
</div>

View File

@ -112,29 +112,41 @@ WebSocketObserver().listener('server/console/remove', (data) => {
});
//缓冲区定时发送频率,默认限制两秒刷新缓冲区
let consoleBuffer = {};
// 缓冲区定时发送频率,默认限制两秒刷新缓冲区
const consoleBuffer = {};
setInterval(() => {
for (const serverName in consoleBuffer) {
let data = consoleBuffer[serverName];
// 记录日志历史记录
const logHistory = serverModel.ServerManager().getServer(serverName).logHistory;
if (logHistory) logHistory.writeLine(data)
// 发送前端的标准,前端只识别 \r\n ,不可是\n
data = data.replace(/\n/gim, '\r\n');
data = data.replace(/\r\r\n/gim, '\r\n');
//刷新每个服务器的缓冲数据
selectWebsocket(serverName, (socket) => {
socket.send({
ws: socket.ws,
resK: 'server/console/ws',
resV: {},
body: data
try {
let data = consoleBuffer[serverName];
const server = serverModel.ServerManager().getServer(serverName);
// 此实例可能已经失去联系,可能被删除,可能被改名
if (!server || !data) {
consoleBuffer[serverName] = undefined;
delete consoleBuffer[serverName];
continue;
}
const logHistory = server.logHistory;
if (logHistory) logHistory.writeLine(data)
// 发送前端的标准,前端只识别 \r\n ,不可是\n
data = data.replace(/\n/gim, '\r\n');
data = data.replace(/\r\r\n/gim, '\r\n');
//刷新每个服务器的缓冲数据
selectWebsocket(serverName, (socket) => {
socket.send({
ws: socket.ws,
resK: 'server/console/ws',
resV: {},
body: data
});
});
});
// 释放内存
consoleBuffer[serverName] = "";
// 释放内存并删除键
consoleBuffer[serverName] = undefined;
delete consoleBuffer[serverName];
} catch (error) {
MCSERVER.log('实例', serverName, '日志周期性广播任务错误:');
console.log(error);
continue;
}
}
}, MCSERVER.localProperty.console_send_times);
//控制台标准输出流

View File

@ -5,6 +5,7 @@ const permssion = require('../../../helper/Permission');
const serverModel = require('../../../model/ServerModel');
const response = require('../../../helper/Response');
const HISTORY_SIZE_LINE = 1024;
// 正序历史记录路由
WebSocketObserver().listener('server/console/history', (data) => {
@ -18,14 +19,16 @@ WebSocketObserver().listener('server/console/history', (data) => {
response.wsSend(data.ws, 'server/console/history', 'terminalBack', "[控制面板]: 暂无任何历史记录.\r\n");
return;
}
let sendText = logHistory.readLine(userName, 30);
if (sendText) {
sendText = sendText.replace(/\n/gim, '\r\n');
sendText = sendText.replace(/\r\r\n/gim, '\r\n');
response.wsSend(data.ws, 'server/console/history', 'terminalBack', sendText);
} else {
response.wsSend(data.ws, 'server/console/history', 'terminalBack', "[控制面板]: 无法再读取更多的服务端日志.\r\n");
}
logHistory.readLine(userName, HISTORY_SIZE_LINE, (sendText) => {
if (sendText) {
sendText = sendText.replace(/\n/gim, '\r\n');
sendText = sendText.replace(/\r\r\n/gim, '\r\n');
response.wsSend(data.ws, 'server/console/history', 'terminalBack', sendText);
} else {
response.wsSend(data.ws, 'server/console/history', 'terminalBack', "[控制面板]: 无法再读取更多的服务端日志.\r\n");
}
});
}
});
@ -40,12 +43,14 @@ WebSocketObserver().listener('server/console/history_reverse', (data) => {
const logHistory = serverModel.ServerManager().getServer(serverName).logHistory;
if (!logHistory)
return;
let sendText = logHistory.readLineReverse(userName, 50, true);
if (sendText) {
sendText = sendText.replace(/\n/gim, '\r\n');
sendText = sendText.replace(/\r\r\n/gim, '\r\n');
response.wsSend(data.ws, 'server/console/history', 'terminalBack', sendText);
}
logHistory.readLineReverse(userName, HISTORY_SIZE_LINE, true, (sendText) => {
if (sendText) {
sendText = sendText.replace(/\n/gim, '\r\n');
sendText = sendText.replace(/\r\r\n/gim, '\r\n');
response.wsSend(data.ws, 'server/console/history', 'terminalBack', sendText);
}
});
}
});