node.js mongodb日志分析系统实现教程

发布时间:2020-11-25编辑:脚本学堂
node.js与mongodb实现简单日志分析系统的一段代码,前端用js,服务器用js,就连数据库的shell都是js,最关键是代码量小,需要的朋友参考下。

为了便于分析把项目的日志都存成了json格式。之前日志直接存在了文件中,而mongodb适时闯入了我的视线,于是就把log存进了mongodb中。
log只存起来是没有意义的,最关键的是要从日志中发现业务的趋势、系统的性能漏洞等。

之前有一个用java写的分析模块,运行在tomcat下。

实现相当的重量级,添加一个新指标的流程也比较繁琐,而且由于nfs的原因还导致分析失败。
前端用js,服务器用js,就连数据库shell都是js,最关键是代码量小。

一、用node.js实现服务器端代码
为了有良好的风格和快速的代码编写,不可避免地应该采用一个简单的框架。Express实现了大部分的功能,可是好需要花一定时间熟悉,并且看起来对这个项目来说有些重量级。在Node.js的官网上有一个聊天的Demo,这个代码简单移动,封装了对URL的处理和返回JSON。于是我就直接使用了fu.js,重写了server.js:
 

复制代码 代码示例:
HOST = null; // localhost
PORT = 8001;
 
var fu = require("./fu"),
sys = require("util"),
url = require("url"),
mongo = require("./request_handler");
 
fu.listen(Number(process.env.PORT || PORT), HOST);
 
fu.get("/", fu.staticHandler("index.html"));
 

一个服务器已经建立起来了。

处理请求的request_handler.js代码:
 

复制代码 代码示例:

var mongodb = require("mongodb");
var fu = require("./fu");
 
// TOP 10 user Action
fu.get("/userActionTop10", function(req, res){
mongodb.connect(‘mongodb://localhost:27017/log‘, function(err, conn){
conn.collection(‘action_count‘, function(err, coll){
coll.find({"value.action":{$in:user_action}}).sort({"value.count":-1}).limit(10).toArray(function(err, docs){
if(!err){
var action = [];
var count = [];
for(var i = 0; i < docs.length; i ++){
//console.log(docs[i]);
action.push(docs[i].value.action);
count.push(docs[i].value.count);
}
res.simpleJSON(200, {action:action, count:count});

// 一定要记得关闭数据库连接
conn.close();
}
});
});
});
});
 

同样很简单。

二、客户端
日志系统的最重要的是可视化显示,这里使用了jquery的一个插件jqPlot Chart。首先使用一个静态的HTML页面,用来作为图形显示的容器:
 

复制代码 代码示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Rendezvous Monitor System</title>
<!–[if lt IE 9]><script src="js/excanvas.js"><![endif]–>
<script src="js/jquery.min.js"></script>
<script src="js/jquery.jqplot.min.js"></script>
<script src="js/plugins/jqplot.barRenderer.min.js"></script>
<script src="js/plugins/jqplot.categoryAxisRenderer.min.js"></script>
<script src="js/plugins/jqplot.canvasTextRenderer.min.js"></script>
<script src="js/plugins/jqplot.canvasAxisTickRenderer.min.js"></script>
<script src="js/plugins/jqplot.canvasAxisLabelRenderer.min.js"></script>
<script src="js/plugins/jqplot.pointLabels.min.js"></script>
<script src="js/plugins/jqplot.dateAxisRenderer.min.js"></script>
<script src="js/plugins/jqplot.json2.min.js"></script>
<link rel="stylesheet" href="js/jquery.jqplot.min.css">
<link rel="stylesheet" href="style/base.css">
<script src="js/charts.js"></script>
</head>
<body>
</body>
</html>
 

几乎是jqPlot的示例中的完整拷贝。

显示生成图形的chart.js:
 

复制代码 代码示例:
// Store all chart drawing function, if we want to disable one chart, only need
// comment the push line when putting fucntion into the array.
var draws = [];
/****************************** TOP 10 User Action Start *********************************/
document.write(‘<div id="userActionTop10Chart"></div>‘);
var drawUserActionTop10Chart = function(){
if(!$("#userActionTop10Chart").attr(‘class‘)){
$("#userActionTop10Chart").attr(‘class‘, ‘small_chart‘);
}
$.ajax({
async:false,
url: ‘/userActionTop10‘,
dataType:‘json‘,
cache: false,
success:function(data){
try{
$(‘#userActionTop10Chart‘).html(”);
$.jqplot(‘userActionTop10Chart‘, [data.count], {
title: "TOP 10 User Action",
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
rendererOptions: {fillToZero: true},
pointLabels: {
show:true,
ypadding:1
}
},
axesDefaults:{
tickRenderer:$.jqplot.CanvasAxisTickRenderer,
tickOptions: {
angle: -30,
fontSize: ‘12px‘
}
},
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: data.action
},
yaxis: {
pad: 1.05
}
}
});
}catch(e){
//alert(e.message);
}
}
});
}
draws.push(‘drawUserActionTop10Chart‘);
/******************************* TOP 10 User Action End ************************************/
/*********** Chart Start *****************/
//Put your chart drawing function here
//1. insert a div for the chart
//2. implement the function drawing chart
//3. push the function name into the array draws
/*********** Chart End *******************/
// Draw all charts
var drawAllCharts = function(){
for(var i = 0; i < draws.length; i ++){
eval(draws[i] + "()");
}
 //Recall itself in 5 minute.
 window.setTimeout(drawAllCharts, 5 * 60 * 1000);
}
//
$(function(){
drawAllCharts();
});
 

服务器端和客户端的代码都有了,那就跑起来看效果吧:

node.js mongodb<a href=http://www.jb200.com/zt/rizhifenxi/ target=_blank class=infotextkey>日志分析</a>系统

日志的分析代码。

三、使用MongoDB 增量式MapReduce实现日志分析
在MongoDB的文档中有关于Incremental MapReduce的介绍。刚开始一直以为MongoDB实现Streaming处理,可以自动执行增量式的MapReduce。最后发现原来是我理解有误,文档里并没有写这一点,只是说明了如何设置才能增量执行MapReduce。

把MapReduce使用MongoDB的javascript写在了单独的js文件中,然后通过crontab定时执行。

stats.js代码:
 

复制代码 代码示例:
/************** The file is executed per 5 minutes by /etc/crontab.*****************/
var action_count_map = function(){
emit(this.action, {action:this.action, count:1});
}
 
var action_count_reduce = function(key, values){
var count = 0;
values.forEach(function(value){
count += value.count;
});
return {action:key, count : count};
}
 
db.log.mapReduce(action_count_map, action_count_reduce, {query : {‘action_count‘ : {$ne:1}},out: {reduce:‘action_count‘}});
 
db.log.update({‘action_count‘:{$ne:1}}, {$set:{‘action_count‘:1}}, false, true);
 

思路:
1、在map中将每个action访问次数设为1
2、reduce中,统计相同action的访问次数
3、执行mapReduce。指定了查询为‘action_count’不等于1,也就是没有执行过该统计;将结果存储在‘action_count’集合,并且使用reduce选项表示该结果集作为下次reduce的输入。
4、在当前所有日志记录设置’action_count’的值为1,表示已经执行过该统计。不知道这种是否会造成没有还没有统计过的记录也被更新?望有经验的大侠赐教!

定时执行stats.js的shell:
 

*/5 * * * * root cd /root/log; mongo localhost:27017/log stats.js