本篇文章给大家分享的是有关使用NodeJS怎么读取分析Nginx错误日志,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
错误日志分析
首先我们要读取Nginx日志,我们可以看到Nginx的错误日志格式一般都是这样子,需要注意的是Nginx的错误日志格式是差不多的因为无法设置日志格式只能设置日志错误等级所以我们分析的时候很方便
这里我们用到readline
逐行读取,简单来说可以做
实现方法
const readline = require('readline');
const fs = require('fs');
const path = require('path');
console.time('readline-time')
const rl = readline.createInterface({
input: fs.createReadStream(path.join(__dirname, '../public/api.err.log'), {
start: 0,
end: Infinity
}),
});
let count = 0;
rl.on('line', (line) => {
const arr = line.split(', ');
const time = arr[0].split('*')[0].split('[')[0].replace(/\//g, '-');//获取到时间
const error = arr[0].split('*')[1].split(/\d\s/)[1];//错误原因
const client = arr[1].split(' ')[1];//请求的客户端
const server = arr[2].split(' ')[1];//请求的网址
const url = arr[3].match(/\s\/(\S*)\s/)[0].trim()//获取请求链接
const upstream = arr[4].match(/(?<=").*?(?=")/g)[0];//获取上游
const host = arr[5].match(/(?<=").*?(?=")/g)[0];//获取host
const referrer = arr[6] ? arr[6].match(/(?<=").*?(?=")/g)[0] : '';//来源
console.log(`时间:${time}-原因:${error}-客户端:${client}-网址:${server}-地址:${url}-上游:${upstream}-主机:${host}-来源:${referrer}`);
count++;
});
rl.on('close', () => {
let size = fs.statSync(path.join(__dirname, '../public/api.err.log')).size;
console.log(`读取完毕:${count};文件位置:${size % 2 === 0}`);
console.timeEnd('readline-time')
});
上面代码有几点需要注意的是会创建一个文件可读流然后由于演示所以我是直接找的本地地址如果是生产环境的话大家可以直接填写服务器上的错误日志地址,如果没有Nginx错误日志分割的话每天会产生很多日志,createReadStream读取几十M的文件还好如果读取几百M或者上G的容量日志这会造成性能问题,所以我们需要在每次createReadStream没必要每次从0字节开始读取,ceateReadStream提供了start和end
所以我们每次可以在读取完之后记录一下当前文件字节大小下一次读取文件就是可以用该文件上次的大小开始读取
let size = fs.statSync(path.join(__dirname, '../public/api.err.log')).size;
我们可以对比一下每次从0字节开始读取和从指定字节读取
保存数据进行分析
这里我是用node-schedule
这个库进行定时保存错误日志和linux的cron差不多,用的mongodb保存数据,这里更推荐大家用elasticsearch来做日志分析
rl.on('close', async () => {
let count = 0;
for (let i of rlist) {
count++;
if (count % 500 === 0) {
const res = await global.db.collection('logs').bulkWrite(rlist.slice(count, count + 500), { ordered: false, w: 1 }).catch(err => { console.error(`批量插入出错${err}`) });
} else if (count === rlist.length - 1) {
//批量插入 数据
const res = await global.db.collection('logs').bulkWrite(rlist.slice(rlist - (rlist % 500), rlist.length), { ordered: false, w: 1 });
let size = fs.statSync(addres).size;
size = size % 2 === 0 ? size : size + 1;//保证字节大小是偶数 不然会出现读取上行内容不完整的情况
count = 0;
rlist.length = [];
//更新数据库里面文件的size
global.db.collection('tasks').updateOne({ _id: addre }, { $set: { _id: addre, size, date: +new Date() } }, { upsert: true });
}
}
resolve(true);
})
上面主要是500条保存一次,因为我用的是批量插入然后mongodb有限制一次性最多插入16M数据的限制,所以大家看自己清空决定一次性插入多少条 犹豫对readline的实现比较感兴趣,就去翻阅了一下源码发现并不是我们想的那么复杂, readline源码 ,下面贴一下line事件的源码,想继续深入的同学可以看看全部的源码
if (typeof s === 'string' && s) {
var lines = s.split(/\r\n|\n|\r/);
for (var i = 0, len = lines.length; i < len; i++) {
if (i > 0) {
this._line();
}
this._insertString(lines[i]);
}
}
...
Interface.prototype._line = function() {
const line = this._addHistory();
this.clearLine();
this._onLine(line);
};
...
Interface.prototype._onLine = function(line) {
if (this._questionCallback) {
var cb = this._questionCallback;
this._questionCallback = null;
this.setPrompt(this._oldPrompt);
cb(line);
} else {
this.emit('line', line);
}
};
保存的数据需要进行分析比如哪个IP访问最多哪条错误最多可以用聚合来进行分析贴出示例分析某个IP在某一天访问出错最多的原因
db.logs.aggregate(
// Pipeline
[
// Stage 1
{
$group: {
'_id': { 'client': '114.112.163.28', 'server': '$server', 'error': '$error', 'url': '$url', 'upstream': '$upstream','date':'$date' ,'msg':'$msg' } ,
'date':{'$addToSet':'$date'},
count: { '$sum': 1 }
}
},
// Stage 2
{
$match: {
count: { $gte: 1 },
date: ['2019-05-10']
}
},
{
$sort: {
count: -1
}
},
],
// Options
{
cursor: {
batchSize: 50
},
allowDiskUse: true
}
);
以上就是使用NodeJS怎么读取分析Nginx错误日志,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注天达云行业资讯频道。