blob: e80d77335caf2b2fef2d63a3918e4fa8fb98c093 [file] [log] [blame]
/*
* Copyright (c) 2013 DataTorrent, Inc. ALL Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var redis = require('redis');
var dateFormat = require('dateformat');
var async = require('async');
var config = require('../config');
var client;
var demoEnabled = (config.siteops.redis.port && config.siteops.redis.host);
if (demoEnabled) {
client = redis.createClient(config.siteops.redis.port, config.siteops.redis.host);
}
exports.index = function(req, res) {
if (demoEnabled) {
res.render('siteops');
} else {
res.render('error', {
message: 'Site Operations Demo is not enabled. Please configure Redis.'
});
}
};
exports.clientData = function(req, res) {
var service = new RedisService(client, 9);
service.fetchValue(function(result) {
res.json(result);
});
};
exports.totalViews = function(req, res) {
var service = new RedisService(client, 11);
service.fetchValue(function(result) {
res.json(result);
});
};
exports.topUrlData = function(req, res) {
var service = new RedisService(client, 2);
service.fetchTop10(function(result) {
res.json(result);
});
};
exports.topServer = function(req, res) {
var service = new RedisService(client, 10);
service.fetchTop10(function(result) {
res.json(result);
});
};
exports.topIpData = function(req, res) {
var service = new RedisService(client, 6);
service.fetchTop10(function(result) {
res.json(result);
});
};
exports.server404 = function(req, res) {
var service = new RedisService(client, 8);
service.fetchTop10(function(result) {
res.json(result);
});
};
exports.topIpClientData = function(req, res) {
var service = new RedisService(client, 3);
service.fetchTop10(function(result) {
res.json(result);
});
};
exports.url404 = function(req, res) {
var service = new RedisService(client, 7);
service.fetchTop10(function(result) {
res.json(result);
});
};
exports.pageViewTimeData = function(req, res) {
fetchPageViews(req.query, function(err, result) {
res.json(result);
});
};
exports.serverLoad = function(req, res) {
fetchServerLoad(req.query, function(err, result) {
res.json(result);
});
};
function fetchPageViews(query, resCallback) {
var lookbackHours = query.lookbackHours;
var url = query.url;
var endTime = Date.now();
var pageKeyTemplate = 'm|$date|0:mydomain.com/$page';
var urlKeyTemplate = 'm|$date|0:$url';
var minute = (60 * 1000);
var result = [];
var keyTemplate;
var minuteKeysFn;
if (url) {
minuteKeysFn = function(key) { return [key] }; // 1 key
keyTemplate = 'm|$date|0:$url'.replace('$url', url);
} else {
minuteKeysFn = getPageViewsMinuteKeys;
keyTemplate = 'm|$date|0:mydomain.com/$page';
}
var service = new RedisService(client, 1);
var time = endTime - lookbackHours * (60 * minute);
// fetch all minutes serially within lookback period
async.whilst(
function() { return time < endTime; },
function(callback) {
var date = dateFormat(time, 'UTC:yyyymmddHHMM');
var minuteKeyTemplate = keyTemplate.replace('$date', date);
var keys = minuteKeysFn(minuteKeyTemplate);
service.fetchMinuteTotals(keys, time, function(item) {
result.push(item);
callback();
});
time += minute;
},
function (err) {
resCallback(err, result);
}
);
}
function fetchServerLoad(query, resCallback) {
var lookbackHours = query.lookbackHours;
var server = query.server;
var minute = (60 * 1000);
var result = [];
var keyTemplate;
var minuteKeysFn;
if (server) {
minuteKeysFn = function(key) { return [key] }; // 1 key
keyTemplate = 'm|$date|0:$server'.replace('$server', server);
} else {
minuteKeysFn = getServerLoadMinuteKeys;
keyTemplate = 'm|$date|0:server$i.mydomain.com:80';
}
var endTime = Date.now();
endTime -= (endTime % minute); // round to minute
var time = endTime - lookbackHours * (60 * minute);
var service = new RedisService(client, 4);
// fetch all minutes serially within lookback period
async.whilst(
function() { return time < endTime; },
function(callback) {
var date = dateFormat(time, 'UTC:yyyymmddHHMM');
var minuteKeyTemplate = keyTemplate.replace('$date', date);
var keys = minuteKeysFn(minuteKeyTemplate);
service.fetchMinuteTotals(keys, time, function(item) {
result.push(item);
callback();
});
time += minute;
},
function (err) {
resCallback(err, result);
}
);
}
function getPageViewsMinuteKeys(keyTemplate) {
var keys = [];
var pages = ['home.php', 'contactus.php', 'about.php', 'support.php', 'products.php', 'services.php', 'partners.php'];
pages.forEach(function(page) {
var key = keyTemplate.replace('$page', page);
keys.push(key);
});
return keys;
}
function getServerLoadMinuteKeys(keyTemplate) {
var keys = [];
for (var i = 0; i < 10; i++) {
var key = keyTemplate.replace('$i', i);
keys.push(key);
}
return keys;
}
function RedisService(client, dbIndex) {
this.client = client;
this.dbIndex = dbIndex;
}
RedisService.prototype.fetchMinuteTotals = function(keys, time, callback) {
var multi = this.client.multi();
multi.select(this.dbIndex);
keys.forEach(function(key) {
multi.hgetall(key);
});
multi.exec(function (err, replies) {
// reply 0 - select command
// reply 1..n - hgetall commands
var total = 0;
for (var i = 1; i < replies.length; i++) {
var hash = replies[i];
if (hash) {
total += parseInt(hash[1]);
}
}
var item = {
timestamp: time,
view: total
}
callback(item);
});
}
RedisService.prototype.fetchValue = function (callback) {
var multi = this.client.multi();
multi.select(this.dbIndex);
multi.get(1);
multi.exec(function (err, replies) {
var value = parseInt(replies[1]);
callback(value);
});
}
RedisService.prototype.fetchTop10 = function(callback) {
var multi = this.client.multi();
multi.select(this.dbIndex);
for (var i = 0; i < 10; i++) {
multi.get(i);
}
multi.exec(function (err, replies) {
// reply 0 - select command
// reply 1..n - get commands
var top10 = replies.slice(1);
callback(top10);
});
}