mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-07 14:35:47 +01:00
Squashed commit of the following:
commit 49e6c0040cc82c1e2684933a8e167ef14854aff8 Author: Julian Lam <julian@designcreateplay.com> Date: Thu Feb 25 16:12:15 2016 -0500 added recording and charts for topic and post counts globally and by cid commit e02ff70757f778aa016fbc42ef10a5da2d07a9d9 Author: Julian Lam <julian@designcreateplay.com> Date: Thu Feb 25 15:35:49 2016 -0500 added labels to charts commit e75d83bf3886e5183bcf5fcd848d71c513761e01 Author: Julian Lam <julian@designcreateplay.com> Date: Thu Feb 25 13:30:47 2016 -0500 added per category graphs to ACP management page commit e3f543200950925cc9e8bf33cccb592f949a100e Author: Julian Lam <julian@designcreateplay.com> Date: Thu Feb 25 12:36:11 2016 -0500 updated analytics to move helper methods to analytics lib and sending per category analytics to ACP page commit 01891d8f7c408925fcdad18dcaa941e5ebbeb9b2 Author: Julian Lam <julian@designcreateplay.com> Date: Wed Feb 24 16:48:55 2016 -0500 saving per-category analytics, and updated the writeData method to use async for "clarity"
This commit is contained in:
131
src/analytics.js
131
src/analytics.js
@@ -1,23 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
var cronJob = require('cron').CronJob;
|
||||
var async = require('async');
|
||||
|
||||
var db = require('./database');
|
||||
|
||||
(function(Analytics) {
|
||||
var counters = {};
|
||||
|
||||
var pageViews = 0;
|
||||
var uniqueIPCount = 0;
|
||||
var uniquevisitors = 0;
|
||||
|
||||
var isCategory = /^(?:\/api)?\/category\/(\d+)/;
|
||||
|
||||
new cronJob('*/10 * * * *', function() {
|
||||
Analytics.writeData();
|
||||
}, null, true);
|
||||
|
||||
Analytics.pageView = function(ip) {
|
||||
Analytics.increment = function(keys) {
|
||||
keys = Array.isArray(keys) ? keys : [keys];
|
||||
|
||||
keys.forEach(function(key) {
|
||||
counters[key] = counters[key] || 0;
|
||||
++counters[key];
|
||||
});
|
||||
};
|
||||
|
||||
Analytics.pageView = function(payload) {
|
||||
++pageViews;
|
||||
|
||||
if (ip) {
|
||||
db.sortedSetScore('ip:recent', ip, function(err, score) {
|
||||
if (payload.ip) {
|
||||
db.sortedSetScore('ip:recent', payload.ip, function(err, score) {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
@@ -28,40 +42,116 @@ var db = require('./database');
|
||||
today.setHours(today.getHours(), 0, 0, 0);
|
||||
if (!score || score < today.getTime()) {
|
||||
++uniquevisitors;
|
||||
db.sortedSetAdd('ip:recent', Date.now(), ip);
|
||||
db.sortedSetAdd('ip:recent', Date.now(), payload.ip);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (payload.path) {
|
||||
var categoryMatch = payload.path.match(isCategory),
|
||||
cid = categoryMatch ? parseInt(categoryMatch[1], 10) : null;
|
||||
|
||||
if (cid) {
|
||||
Analytics.increment(['pageviews:byCid:' + cid]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Analytics.writeData = function() {
|
||||
var today = new Date();
|
||||
var month = new Date();
|
||||
var dbQueue = [];
|
||||
|
||||
var today;
|
||||
if (pageViews > 0 || uniquevisitors > 0) {
|
||||
today = new Date();
|
||||
today.setHours(today.getHours(), 0, 0, 0);
|
||||
}
|
||||
today.setHours(today.getHours(), 0, 0, 0);
|
||||
month.setMonth(month.getMonth(), 1);
|
||||
month.setHours(0, 0, 0, 0);
|
||||
|
||||
if (pageViews > 0) {
|
||||
db.sortedSetIncrBy('analytics:pageviews', pageViews, today.getTime());
|
||||
var month = new Date();
|
||||
month.setMonth(month.getMonth(), 1);
|
||||
month.setHours(0, 0, 0, 0);
|
||||
db.sortedSetIncrBy('analytics:pageviews:month', pageViews, month.getTime());
|
||||
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:pageviews', pageViews, today.getTime()));
|
||||
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:pageviews:month', pageViews, month.getTime()));
|
||||
pageViews = 0;
|
||||
}
|
||||
|
||||
if (uniquevisitors > 0) {
|
||||
db.sortedSetIncrBy('analytics:uniquevisitors', uniquevisitors, today.getTime());
|
||||
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:uniquevisitors', uniquevisitors, today.getTime()));
|
||||
uniquevisitors = 0;
|
||||
}
|
||||
|
||||
if (uniqueIPCount > 0) {
|
||||
db.incrObjectFieldBy('global', 'uniqueIPCount', uniqueIPCount);
|
||||
dbQueue.push(async.apply(db.incrObjectFieldBy, 'global', 'uniqueIPCount', uniqueIPCount));
|
||||
uniqueIPCount = 0;
|
||||
}
|
||||
|
||||
if (Object.keys(counters).length > 0) {
|
||||
for(var key in counters) {
|
||||
console.log('flushing', key, 'with a value of', counters[key]);
|
||||
dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:' + key, counters[key], today.getTime()));
|
||||
delete counters[key];
|
||||
}
|
||||
}
|
||||
|
||||
async.parallel(dbQueue, function(err) {
|
||||
if (err) {
|
||||
winston.error('[analytics] Encountered error while writing analytics to data store: ' + err.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Analytics.getHourlyStatsForSet = function(set, hour, numHours, callback) {
|
||||
var terms = {},
|
||||
hoursArr = [];
|
||||
|
||||
hour = new Date(hour);
|
||||
hour.setHours(hour.getHours(), 0, 0, 0);
|
||||
|
||||
for (var i = 0, ii = numHours; i < ii; i++) {
|
||||
hoursArr.push(hour.getTime());
|
||||
hour.setHours(hour.getHours() - 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
db.sortedSetScores(set, hoursArr, function(err, counts) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
hoursArr.forEach(function(term, index) {
|
||||
terms[term] = parseInt(counts[index], 10) || 0;
|
||||
});
|
||||
|
||||
var termsArr = [];
|
||||
|
||||
hoursArr.reverse();
|
||||
hoursArr.forEach(function(hour) {
|
||||
termsArr.push(terms[hour]);
|
||||
});
|
||||
|
||||
callback(null, termsArr);
|
||||
});
|
||||
};
|
||||
|
||||
Analytics.getDailyStatsForSet = function(set, day, numDays, callback) {
|
||||
var daysArr = [];
|
||||
|
||||
day = new Date(day);
|
||||
day.setDate(day.getDate()+1); // set the date to tomorrow, because getHourlyStatsForSet steps *backwards* 24 hours to sum up the values
|
||||
day.setHours(0, 0, 0, 0);
|
||||
|
||||
async.whilst(function() {
|
||||
return numDays--;
|
||||
}, function(next) {
|
||||
Analytics.getHourlyStatsForSet(set, day.getTime()-(1000*60*60*24*numDays), 24, function(err, day) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
daysArr.push(day.reduce(function(cur, next) {
|
||||
return cur+next;
|
||||
}));
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
callback(err, daysArr);
|
||||
});
|
||||
};
|
||||
|
||||
Analytics.getUnwrittenPageviews = function() {
|
||||
@@ -86,4 +176,13 @@ var db = require('./database');
|
||||
});
|
||||
};
|
||||
|
||||
Analytics.getCategoryAnalytics = function(cid, callback) {
|
||||
async.parallel({
|
||||
'pageviews:hourly': async.apply(Analytics.getHourlyStatsForSet, 'analytics:pageviews:byCid:' + cid, Date.now(), 24),
|
||||
'pageviews:daily': async.apply(Analytics.getDailyStatsForSet, 'analytics:pageviews:byCid:' + cid, Date.now(), 30),
|
||||
'topics:daily': async.apply(Analytics.getDailyStatsForSet, 'analytics:topics:byCid:' + cid, Date.now(), 7),
|
||||
'posts:daily': async.apply(Analytics.getDailyStatsForSet, 'analytics:posts:byCid:' + cid, Date.now(), 7),
|
||||
}, callback);
|
||||
};
|
||||
|
||||
}(exports));
|
||||
Reference in New Issue
Block a user