有这样一个需求,想要通过
websocket
查看某些日志文件的输出(新的文件,或者是新添加的内容,可以按行输出),并且需要实时的,可采用系统的tail
并结合spawn
命令进行。
使用方法
package.json
{
"name": "logs",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"koa": "^2.5.1",
"koa-body": "^4.0.3",
"koa-route": "^3.2.0",
"koa-websocket": "^5.0.1",
"uuid": "^3.3.2",
"watch": "^1.0.2"
}
}
安装
npm install
index.js
let fs = require('fs');
let spawn = require('child_process').spawn;
let watch = require('watch');
let uuid = require('uuid/v4');
const Koa = require('koa'),
route = require('koa-route'),
websockify = require('koa-websocket');
let dataFormat = require('./format.js');
const logPath = './logdir';
const port = 3001;
const app = websockify(new Koa());
let wsClients = new Map();
var tail = null;
let fun = function () {
let dayPath = "20181023/127.0.0.1";
if (tail != null) {
try {
tail.kill('SIGHUP');
} catch (e) {
console.log("tail程序关闭异常");
}
}
if (fs.existsSync(`${logPath}/${dayPath}`)) {
let filenames = fs.readdirSync(`${logPath}/${dayPath}`).filter(name => {
return name.startsWith(("0" + new Date().getHours()).slice(-2) + "_")
}).map(function (file) {
return `${logPath}/${dayPath}/${file}`
});
tail = spawn("tail", ["-f"].concat(filenames));
tail.stdout.on("data", function (data) {
for (let filter of wsClients.values()) {
try {
filter(data.toString("utf-8"))
} catch (e) {
console.log(e);
}
}
});
} else {
console.log(logPath + '/' + dayPath + '路径不存在');
}
};
let preCreateTime = 0;
watch.watchTree(logPath, function (f, curr, prev) {
if (typeof f == "object" && prev === null && curr === null) {
} else if (prev === null) {
if ((new Date() - preCreateTime) > 1000) {
fun();
}
preCreateTime = new Date().getTime()
}
});
app.ws.use(function (ctx, next) {
return next(ctx);
});
app.ws.use(route.all('/logs/:appKey/:openId', function (ctx) {
let appKey = ctx.url.split("/")[2];
let openId = ctx.url.split("/")[3];
if (openId.indexOf("*") != -1 || appKey.indexOf("*") != -1) {
ctx.websocket.send(JSON.stringify({status: 'fail', msg: '(openId|appKey)禁止使用正则表达式,请检查'}));
ctx.websocket.close();
return;
}
let clientId = uuid();
wsClients.set(clientId, function (data) {
if (data && data.indexOf(appKey) != -1 && data.indexOf(openId) != -1) {
data.split("\n").forEach(line => {
if (line && line.indexOf(appKey) != -1 && line.indexOf(openId) != -1) {
try {
ctx.websocket.send(line);
} catch (e) {
console.log('发送异常');
}
}
})
}
});
ctx.websocket.on('close', function () {
wsClients.delete(clientId);
});
ctx.websocket.on('error', function () {
wsClients.delete(clientId);
console.log('连接异常.');
});
ctx.websocket.on('message', function (message) {
if (message === 'online') {
ctx.websocket.send(JSON.stringify({status: 'success', msg: '当前在线人数:' + wsClients.size}));
} else if (message === 'id') {
ctx.websocket.send("你的id为:" + clientId);
}
});
}));
app.listen(port, function () {
console.log(`files online tail listener port ${port}`);
fun();
});
假设logdir
目录结构如下
├── 20181023
│ └── 127.0.0.1
│ ├── 19_1.log
│ └── 20_2.log
使用chrome的socket client即可查看新增文件或修改文件的内容
可以说,由于调用系统的tail命令,基本是零延迟输出的。
网友评论