NodeJS读取分析Nginx错误日志的方法


Posted in NodeJs onMay 14, 2019

网上很少看到有用NodeJS运维系列文章,后续我会更新一些NodeJS运维相关的内容又或者说让我们更加的深入了解一些服务器的知识以及自动化运维方面的基础知识 为什么要做错误日志分析,因为网上这方面的工具不多我找到一个goaccess但是都是分析成功日志以及用户访问趋势,找了半天没找着自己想要的索性就自己利用Node造一个

错误日志分析

首先我们要读取Nginx日志,我们可以看到Nginx的错误日志格式一般都是这样子,需要注意的是Nginx的错误日志格式是差不多的因为无法设置日志格式只能设置日志错误等级所以我们分析的时候很方便

NodeJS读取分析Nginx错误日志的方法

 这里我们用到readline

逐行读取,简单来说可以做

  • 文件逐行读取:比如说进行日志分析。
  • 自动完成:比如输入npm,自动提示"help init install"。
  • 命令行工具:比如npm init这种问答式的脚手架工具。 这里我们主要做日志分析其他的感兴趣可以琢磨一下

实现方法

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

 NodeJS读取分析Nginx错误日志的方法

所以我们每次可以在读取完之后记录一下当前文件字节大小下一次读取文件就是可以用该文件上次的大小开始读取

let size = fs.statSync(path.join(__dirname, '../public/api.err.log')).size;

我们可以对比一下每次从0字节开始读取和从指定字节读取

NodeJS读取分析Nginx错误日志的方法

保存数据进行分析

这里我是用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错误日志的方法,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

NodeJs 相关文章推荐
nodejs npm install全局安装和本地安装的区别
Jun 05 NodeJs
Nodejs爬虫进阶教程之异步并发控制
Feb 15 NodeJs
angular2+nodejs实现图片上传功能
Mar 27 NodeJs
Nodejs 复制文件/文件夹的方法
Aug 24 NodeJs
Mac 安装 nodejs方法(图文详细步骤)
Oct 30 NodeJs
nodejs简单读写excel内容的方法示例
Mar 16 NodeJs
基于Koa(nodejs框架)对json文件进行增删改查的示例代码
Feb 02 NodeJs
NodeJS实现同步的方法
Mar 02 NodeJs
详解nodejs http请求相关总结
Mar 31 NodeJs
nodejs分离html文件里面的js和css的方法
Apr 09 NodeJs
如何利用nodejs实现命令行游戏
Nov 24 NodeJs
分享node.js实现简单登录注册的具体代码
Apr 26 NodeJs
nodejs搭建本地服务器并访问文件操作示例
May 11 #NodeJs
M2实现Nodejs项目自动部署的方法步骤
May 05 #NodeJs
nodejs通过钉钉群机器人推送消息的实现代码
May 05 #NodeJs
nodejs中request库使用HTTPS代理的方法
Apr 30 #NodeJs
详解微信小程序-获取用户session_key,openid,unionid - 后端为nodejs
Apr 29 #NodeJs
nodejs检测因特网是否断开的解决方案
Apr 17 #NodeJs
Nodejs实现用户注册功能
Apr 14 #NodeJs
You might like
ftp类(example.php)
2006/10/09 PHP
jQuery+PHP+ajax实现微博加载更多内容列表功能
2014/06/27 PHP
PHP实现生成透明背景的PNG缩略图函数分享
2014/07/08 PHP
PHP中file_get_contents高?用法实例
2014/09/24 PHP
ThinkPHP中where()使用方法详解
2016/04/19 PHP
php使用json_decode后数字对象转换成了科学计数法的解决方法
2017/02/20 PHP
浅谈Yii乐观锁的使用及原理
2017/07/25 PHP
详解PHP队列的实现
2019/03/14 PHP
PHP7实现和CryptoJS的AES加密方式互通示例【AES-128-ECB加密】
2019/06/08 PHP
js 判断计算字符串长度/判断空的简单方法
2013/08/05 Javascript
jQuery中$.get、$.post、$.getJSON和$.ajax的用法详解
2014/11/19 Javascript
关于input全选反选恶心的异常情况
2016/07/24 Javascript
AngularJS 输入验证详解及实例代码
2016/07/28 Javascript
Google 地图获取API Key详细教程
2016/08/06 Javascript
[Bootstrap-插件使用]Jcrop+fileinput组合实现头像上传功能实例代码
2016/12/20 Javascript
vue使用自定义icon图标的方法
2018/05/14 Javascript
vue 中的keep-alive实例代码
2018/07/20 Javascript
VUE基于NUXT的SSR 服务端渲染
2018/11/30 Javascript
爬虫利器Puppeteer实战
2019/01/09 Javascript
VUE 单页面使用 echart 窗口变化时的用法
2020/07/30 Javascript
[01:22]DOTA2神秘商店携大量周边降临完美大师赛
2017/11/07 DOTA
python解决字典中的值是列表问题的方法
2013/03/04 Python
1 行 Python 代码快速实现 FTP 服务器
2018/01/25 Python
Python 根据日志级别打印不同颜色的日志的方法示例
2019/08/08 Python
详解从Django Allauth中进行登录改造小结
2019/12/18 Python
五种Python转义表示法
2020/11/27 Python
享誉全球的多元化时尚精品购物平台:Farfetch发发奇(支持中文)
2017/08/08 全球购物
Topman美国官网:英国著名的国际平价时尚男装品牌
2017/12/22 全球购物
Urban Decay官方网站:美国化妆品品牌
2020/06/04 全球购物
售后专员岗位职责
2013/12/08 职场文书
旷课检讨书1000字
2014/02/14 职场文书
社区科普工作方案
2014/06/03 职场文书
2015羊年春节慰问信
2015/02/14 职场文书
小学重阳节活动总结
2015/03/24 职场文书
python自动化测试之Selenium详解
2022/03/13 Python
win10如何开启ahci模式?win10开启ahci模式详细操作教程
2022/07/23 数码科技