这4个文章是一个系列的,关于如何配置 StatsD,Graphite以及如何使用两者来显示访问信息:
在上次把StatsD和Graphite搭建完工后,今天就开始深入研究Graphite怎么用了。Graphite默认绑定在80端口,所以直接用浏览器访问就行,左侧是所有的bucket:
假如你要配置的话,可以访问http://<graphite server>/admin/。后的/不能漏!这个是配置界面可以增加删除用户(需要superuser权限,在第二篇博文里面有讲如何创建superuser的),界面是有够丑的:
这个界面的实用性一般,我比较喜欢使用Dashboard界面(点击Dashboard就可以进入):
Dashboard可以保存点击Dashboard-》Save就可以了,点击Finder可以让你加载你保存的Dashboard。
好,下面是我要统计的信息:
1) 用户账号信息,我想知道到底有谁来访问过我的网站,本身statsd不是用来统计这个的,但是为了简单起见,有一个人来访问,我就把他的域账号作为bucket名字,然后increment。
2) 页面的访问计数和页面的渲染时间,这个我使用了timing功能,timing的sum就是10s内页面渲染的总时间,这个没啥用,但是其他两个属性很有用count(用来统计页面访问次数)、upper(用来统计页面渲染大值)。
3) 状态码,这个用来统计出错的次数(404,500)这些。
开始写代码,statsd-client默认提供了一个expressJs的中间件,但是不太符合我的要求,所以我照着他,重写了一个:
var should = require("should"); // For each requested URL (exclude the static resources), we will statistics // 1) Counter: cer.status_codes.* // 2) Timing: timers.cer.pages.* exports.statsdMiddleware = function (statsdClient) { return function (req, res, next) { should.exists(res.locals); should.exists(req.method); var startTime = new Date(); // Shadow end request var end = res.end; res.end = function () { end.apply(res, arguments); // Statistics the status code, especailly for 500, 404 statsdClient.increment('status_codes.' + res.statusCode); var timeElapse = new Date() - startTime; if (req.route && req.route.path) { var path = req.route.path; if (Object.prototype.toString.call(path) === '[object RegExp]') { path = path.source; } if (path === "/") { path = "root"; } if (req.query.productId) { path += '_' + req.query.productId; } // Statistics the page hit count and time to render the page var key = 'pages.' + req.method.toLowerCase() + '_' + path.replace(/:/g, "").replace(/\//, "").replace(/\//g, "_"); statsdClient.timing(key, timeElapse); // Statistics user accounts var user = req.headers["x-iisnode-auth_user"]; if (user) { console.log(user); statsdClient.increment("users." + user.replace(/\\/g, '_')); } } }; next(); }; }
原作者构思很巧妙,把res.end函数替换掉,这样就可以在每次完成HTTP request的时候,进行统计了。我这里的思路是,假如有req.route.path这个属性(这个可以过滤掉一些静态资源的访问),我就格式化一下key,然后发送给statsD。同时也增加2个计数器,一个是status_codes.*,一个是users.*。这个就完成了,还要做的一件事就是把中间件加入到expressJs里面:
var express = require('express') , http = require('http') , path = require('path') , util = require('util') , middlewares = require('./middlewares'); var app = express(); var SDC = new require('statsd-client'); var sdc = new SDC({ host: 'localhost', port: 8125, debug: false }).getChildClient('cer'); app.configure(function () { app.set('env', 'production'); app.set('port', process.env.PORT || 80); app.set('views', __dirname + '/views'); app.set('view engine', 'ejs'); app.use(middlewares.statsdMiddleware(sdc)); app.use(express.favicon()); app.use(express.logger('dev')); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(app.router); app.use(express.static(path.join(__dirname, 'public'))); app.use(express.errorHandler()); });
这么简单,一切就OK了!接下来的事情就是在Dashboard里面做几个统计:
1. 统计1天内所有页面的访问次数:sumSeries(summarize(*.timers.cer.pages.*.count,"1d"))
2. 查看304状态每隔10秒的出现次数(statsD每隔10秒发送一次):stats_counts.cer.status_codes.304
3. 查看所有用户每隔10秒的访问次数:stats_counts.cer.users.*
4. 查看某一个页面每隔10秒的访问总量:*.timers.cer.pages.get_cer_weeklyCrashCount.count
5. 查看某一个页面每隔10秒的大渲染时间: *.timers.cer.pages.*.upper
然后保存这个dashboard为CER_SITE之后,每次就可以通过http://10.31.143.230/dashboard/#CER_SITE来访问了。