网上有用的NodeJS运维文章很少。后续我会更新一些NodeJS运维相关内容,或者让大家对一些服务器知识和自动化运维的基础知识有更深的了解。为什么要做错误日志分析?因为网上这方面的工具不多,我找到了一个goaccess,但是他们都分析了成功日志和用户访问趋势。找了很久,没有找到我想要的,就用Node自己做了一个。
错误日志分析
首先,我们必须阅读Nginx日志。我们可以看到Nginx的错误日志格式一般是这样的。需要注意的是,Nginx的错误日志格式类似,因为我们无法设置日志格式,只能设置日志错误级别,所以我们分析起来非常方便。
这里我们使用readline
一行一行地读,这很简单
逐行读取文件:例如,日志分析。自动完成:例如,输入npm并自动提示“帮助初始化安装”。命令行工具:如npm init,一种问答式脚手架工具。这里主要做日志分析,其他有兴趣的可以琢磨一下实现方法
const readline=require(' readline ');const fs=require(' fs ');const path=require(' path ');console . time(' readline-time ')const rl=readline . createInTerface({ input 3360 fs . createReadStream(path . join(_ _ dirname)'./public/api.err.log '),{ start: 0,end: Infinity }),});让计数=0;rl.on('line ',(line)={ const arr=line.split(',');常量时间=arr[0]。拆分(' * '[0])。拆分('[')[0]。替换(///g,'-');//获取时间常数错误=arr [0]。拆分(' *') [1]。split(/ d s/)[1];//错误原因const client=arr [1]。split(“”)[1];//请求的客户端const server=arr [2]。split(“”)[1];//请求的URL consturl=arr [3]。匹配(/ s /( s *) s/) [0]。trim()//获取请求的链接const upstream=arr[4]。匹配(/(?=').*?(?=')/g)[0];//获取上游const host=arr[5]。匹配(/(?=').*?(?=')/g)[0];//获取host const referrer=arr[6]?arr[6]。匹配(/(?=').*?(?=')/g)[0]:“”;//source console . log(` time :$ { time }-原因:${error}-客户端:${client}-网站:${server}-地址:${url}-上游:${upstream}-主机: $。计数;});rl.on('close ',()={ let size=fs . statsync(path . join(_ _ dirname,)./public/api.err.log ')。大小;Console.log (` :${count})读取后;文件位置: $ { size % 2===0 } `);console . timeend(' readline-time ')});上面的代码有几点需要注意:它会创建一个文件可读的流,然后因为演示,我会直接找到本地地址。如果是生产环境,可以直接填写服务器上的错误日志地址。如果没有Nginx错误日志分段,每天都会生成很多日志。createReadStream读取数十个M文件。幸运的是,如果它读取数百个M或G容量日志,就会导致性能问题。因此,我们需要每次从0字节读取createReadStream是不必要的,并且ceateReadStream提供了开始和结束
因此,每次读取后我们可以记录当前文件的字节大小,下次读取文件时,我们可以从文件的最后一个大小开始读取
let size=fs . statsync(path . join(_ _ dirname,)./public/api.err.log ')。大小;
我们可以将一次从0字节读取与从指定字节读取进行比较
保存数据以供分析
在这里,我使用node-schedule库定期保存错误日志,类似于linux中的cron,mongodb用于保存数据。在这里,我们推荐弹性搜索来进行日志分析
rl.on('close ',async()={ let count=0;因为(rlist的字母I){ count;if(count % 500===0){ const RES=wait global。db。集合('日志').bulkWrite(rlist.slice(count,count 500),{ ordered: false,w: 1 }).catch(err={ console.error(`批量插入出错$ { err } `) });} else if(count===rlist。长度-1){//批量插入数据const RES=等待全局。db。集合('日志').批量写入(rlist。slice(rlist-(rlist % 500),rlist.length),{ ordered: false,w : 1 });let size=fs.statSync(addres ).大小;size=size % 2===0?尺寸:尺寸1;//保证字节大小是偶数不然会出现读取上行内容不完整的情况计数=0;rlist。长度=[];//更新数据库里面文件的全球规模。db。集合(“任务”).updateOne({ _id: addre }、{ $set: { _id: addre,size,date: new Date() }、{ up sert : true });} }解析(真);})上面主要是500条保存一次,因为我用的是批量插入然后数据库有限制一次性最多插入16M数据的限制,所以大家看自己清空决定一次性插入多少条犹豫对读取线的实现比较感兴趣,就去翻阅了一下源码发现并不是我们想的那么复杂,读取线源码,下面贴一下线条事件的源码,想继续深入的同学可以看看全部的源码
if(s==' string '的类型){ var line=s . split(/ r n | n | r/);for (var i=0,len=lines.length我透镜;I){ if(I 0)}这个. line();}这个_插入字符串(第[i]行);} }.接口。原型。_ line=function(){ const line=this ._ addHistory();这个。clearline();这个_onLine(线路);};接口。原型。_ OnLine=函数(line){ if(this ._questionCallback) { var cb=this ._问题回调这个_ questionCallback=nullthis . setprompt(this ._旧提示);cb(线路);} else { this.emit('line ',line);}};保存的数据需要进行分析比如哪个互联网协议(互联网协议)访问最多哪条错误最多可以用聚合来进行分析贴出示例分析某个互联网协议(互联网协议)在某一天访问出错最多的原因
db。日志。聚合(//Pipeline[//Stage 1 { $ group : { ' _ id ' : { ' client ' : ' 114。112 .163 .28 ',' server': '$server ',' error': '$error ',' url': '$url ',' upstream': '$upstream ',' date ' : ' $ date ',' msg ' : ' $ msg ' },总结
以上所述是小编给大家介绍的开发读取分析Nginx错误日志的方法,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!