使用Node.js + MongoDB实现一个简单的日志分析系统

        在最近的项目中,为了便于分析把项目的日志都存成了JSON格式。之前日志直接存在了文件中,而MongoDB适时闯入了我的视线,于是就把log存进了MongoDB中。log只存起来是没有意义的,最关键的是要从日志中发现业务的趋势、系统的性能漏洞等。之前有一个用Java写的分析模块,运行在Tomcat下。实现相当的重量级,添加一个新指标的流程也比较繁琐,而且由于NFS的原因还导致分析失败。一直想改写,最初想用Ruby On Rails,可是一直没有时间学习和开发(在找借口啊!)。在杭州QCon 2011上又遇到了Node.js,虽然之前也听说过,但是没有深入研究,听了淘宝苏千 的演讲后,当时了就有要用Node.js实现这个日志分析系统的想法。前端用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();
});

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

         好像忘了什么?日志的分析代码。

          三、使用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 

      好了,这就是全部的代码,没有什么特别玄妙的地方,不过Node.js真的是个好东西。

时间: 2024-10-28 05:07:12

使用Node.js + MongoDB实现一个简单的日志分析系统的相关文章

Node.js和MongoDB实现简单日志分析系统

  Node.js和MongoDB实现简单日志分析系统  这篇文章主要介绍了Node.js和MongoDB实现简单日志分析系统,本文给出了服务器端.客户端.图表生成.Shell自动执行等功能的实现代码,需要的朋友可以参考下     在最近的项目中,为了便于分析把项目的日志都存成了JSON格式.之前日志直接存在了文件中,而MongoDB适时闯入了我的视线,于是就把log存进了MongoDB中.log只存起来是没有意义的,最关键的是要从日志中发现业务的趋势.系统的性能漏洞等.之前有一个用Java写的

Node.js和MongoDB实现简单日志分析系统_node.js

在最近的项目中,为了便于分析把项目的日志都存成了JSON格式.之前日志直接存在了文件中,而MongoDB适时闯入了我的视线,于是就把log存进了MongoDB中.log只存起来是没有意义的,最关键的是要从日志中发现业务的趋势.系统的性能漏洞等.之前有一个用Java写的分析模块,运行在Tomcat下.实现相当的重量级,添加一个新指标的流程也比较繁琐,而且由于NFS的原因还导致分析失败.一直想改写,最初想用Ruby On Rails,可是一直没有时间学习和开发(在找借口啊!).在杭州QCon 201

nodejs教程之制作一个简单的文章发布系统_node.js

前言 我们今天就来做一个简单的新闻发布系统,系统第一阶段不需要太难,主要有以下功能 ① 新闻类型管理 ② 新闻管理(具有图片上传功能) ③ 新闻浏览 功能虽然不多,但是也涵盖很多基本操作了,程序不过增删查改嘛,外加上传附件,够了.于是开始我们今天的学习吧 准备工作 根据昨天的折腾后,我们已经有了nodeJS与mongoDB环境了,现在直接新建工程文件与数据库文件即可 第一步,打开命令符切换到D盘后输入 复制代码 代码如下: D:\>express -e news 于是系统会自动开开心心构建基本环

基于高德地图位置的AngularJS+Node.js+MongoDB开发的通讯录实例

有一天班长说了,同学们希望我开发一个可以共享位置的通讯录,于是自己简单设计了下功能.包括用户角色.发表微博.共享位置等等.这次也是有点私心的,为了锻炼最近看的angularjs,于是果断选择Node.js + MongoDB + angular.js的方案.当然,开发Node.js的体会越来越深刻.记得,去年leader告诉我说尽量让node的每一个服务只支撑一个业务功能,这样才能更方便的维护.当时特别想把一个Node服务做的特别强大.现在看来leader的做法是对的,我更加倾向于把node服务

AngularJS + Node.js + MongoDB开发的基于高德地图位置的通讯录_node.js

一.闲扯 有一天班长说了,同学们希望我开发一个可以共享位置的通讯录,于是自己简单设计了下功能.包括用户角色.发表微博.共享位置等等.这次也是有点私心的,为了锻炼最近看的angularjs,于是果断选择Node.js + MongoDB + angular.js的方案.当然,开发Node.js的体会越来越深刻.记得,去年leader告诉我说尽量让node的每一个服务只支撑一个业务功能,这样才能更方便的维护.当时特别想把一个Node服务做的特别强大.现在看来leader的做法是对的,我更加倾向于把n

Node.js的基本知识简单汇总_node.js

Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node.jsS创始人Ryan Dalh加盟Joyent获得企业资助,再到今年发布Windows移植版本,Node.js的前景获得了技术社区的肯定.InfoQ一直在关注Node.js的发展,在今年的两次Qcon大会(北京站和杭州站)都有专门的讲座.为了更好地促进Node.js在国内的技术推广,我们决定开设"深入浅出Node.js"专栏,邀请来自Node.js领域

Node.js DES加密的简单实现_node.js

常见的加密算法基本分为这几类,1 :线性散列算法.2:对称性加密算法.3.非对称性加密算法 (记记记) 线性散列算法(签名算法):MD5,SHA1,HMAC 比如MD5:即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致. 特点: 1.压缩性:任意长度的数据,算出的MD5值长度都是固定的. 2.容易计算:从原数据计算出MD5值很容易. 3.抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别. 4.强抗碰撞:已知原数据

node js-Express node.js 如何访问一个域名 并返回数据求大神指教

问题描述 Express node.js 如何访问一个域名 并返回数据求大神指教 我是要去调用接口 (这个接口是别人写好了的 有自己的域名 我只要传参过去 接口就会返回json数据) 才刚学node.js 想想请教大神 给点思路 或者源代码

我参加了Cloud Foundry博客征文大赛,我的参赛作品是:使用Node.js + Mongodb构建基于Cloud Foundry的项目

问题描述 我参加了CloudFoundry博客征文大赛,我的参赛作品是:使用Node.js+Mongodb构建基于CloudFoundry的项目www.wordmars.netwww.jzjyfc.comwww.fedtr.com 解决方案 解决方案二: 解决方案三: 解决方案四: 解决方案五: 好东西啊,,,,,解决方案六: 解决方案七: 不错,好东西