Port everything related to stats from windshaft
This commit is contained in:
@@ -13,6 +13,10 @@ var NamedMapsCacheEntry = require('./cache/model/named_maps_entry');
|
||||
var VarnishHttpCacheBackend = require('./cache/backend/varnish_http');
|
||||
var FastlyCacheBackend = require('./cache/backend/fastly');
|
||||
|
||||
var StatsClient = require('./stats/client');
|
||||
var Profiler = require('./stats/profiler_proxy');
|
||||
var RendererStatsReporter = require('./stats/reporter/renderer');
|
||||
|
||||
var windshaft = require('windshaft');
|
||||
var mapnik = windshaft.mapnik;
|
||||
|
||||
@@ -46,7 +50,7 @@ var timeoutErrorTile = require('fs').readFileSync(timeoutErrorTilePath, {encodin
|
||||
|
||||
module.exports = function(serverOptions) {
|
||||
// Make stats client globally accessible
|
||||
global.statsClient = windshaft.stats.Client.getInstance(serverOptions.statsd);
|
||||
global.statsClient = StatsClient.getInstance(serverOptions.statsd);
|
||||
|
||||
var redisPool = new RedisPool(_.defaults(global.environment.redis, {
|
||||
name: 'windshaft:server',
|
||||
@@ -156,6 +160,8 @@ module.exports = function(serverOptions) {
|
||||
statsInterval: 60000 // reports stats every milliseconds defined here
|
||||
});
|
||||
var rendererCache = new windshaft.cache.RendererCache(rendererFactory, rendererCacheOpts);
|
||||
var rendererStatsReporter = new RendererStatsReporter(rendererCache, rendererCacheOpts.statsInterval);
|
||||
rendererStatsReporter.start();
|
||||
|
||||
var attributesBackend = new windshaft.backend.Attributes(mapStore);
|
||||
var previewBackend = new windshaft.backend.Preview(rendererCache);
|
||||
@@ -472,7 +478,7 @@ function bootstrap(opts) {
|
||||
|
||||
app.use(function bootstrap$prepareRequestResponse(req, res, next) {
|
||||
req.context = req.context || {};
|
||||
req.profiler = new windshaft.stats.Profiler({
|
||||
req.profiler = new Profiler({
|
||||
statsd_client: global.statsClient,
|
||||
profile: opts.useProfiler
|
||||
});
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
var _ = require('underscore');
|
||||
var debug = require('debug')('windshaft:stats_client');
|
||||
var StatsD = require('node-statsd').StatsD;
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Returns an StatsD instance or an stub object that replicates the StatsD public interface so there is no need to
|
||||
* keep checking if the stats_client is instantiated or not.
|
||||
*
|
||||
* The first call to this method implies all future calls will use the config specified in the very first call.
|
||||
*
|
||||
* TODO: It's far from ideal to use make this a singleton, improvement desired.
|
||||
* We proceed this way to be able to use StatsD from several places sharing one single StatsD instance.
|
||||
*
|
||||
* @param config Configuration for StatsD, if undefined it will return an stub
|
||||
* @returns {StatsD|Object}
|
||||
*/
|
||||
getInstance: function(config) {
|
||||
|
||||
if (!this.instance) {
|
||||
|
||||
var instance;
|
||||
|
||||
if (config) {
|
||||
instance = new StatsD(config);
|
||||
instance.last_error = { msg: '', count: 0 };
|
||||
instance.socket.on('error', function (err) {
|
||||
var last_err = instance.last_error;
|
||||
var last_msg = last_err.msg;
|
||||
var this_msg = '' + err;
|
||||
if (this_msg !== last_msg) {
|
||||
debug("statsd client socket error: " + err);
|
||||
instance.last_error.count = 1;
|
||||
instance.last_error.msg = this_msg;
|
||||
} else {
|
||||
++last_err.count;
|
||||
if (!last_err.interval) {
|
||||
instance.last_error.interval = setInterval(function () {
|
||||
var count = instance.last_error.count;
|
||||
if (count > 1) {
|
||||
debug("last statsd client socket error repeated " + count + " times");
|
||||
instance.last_error.count = 1;
|
||||
//console.log("Clearing interval");
|
||||
clearInterval(instance.last_error.interval);
|
||||
instance.last_error.interval = null;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var stubFunc = function (stat, value, sampleRate, callback) {
|
||||
if (_.isFunction(callback)) {
|
||||
callback(null, 0);
|
||||
}
|
||||
};
|
||||
instance = {
|
||||
timing: stubFunc,
|
||||
increment: stubFunc,
|
||||
decrement: stubFunc,
|
||||
gauge: stubFunc,
|
||||
unique: stubFunc,
|
||||
set: stubFunc,
|
||||
sendAll: stubFunc,
|
||||
send: stubFunc
|
||||
};
|
||||
}
|
||||
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
return this.instance;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
var Profiler = require('step-profiler');
|
||||
|
||||
/**
|
||||
* Proxy to encapsulate node-step-profiler module so there is no need to check if there is an instance
|
||||
*/
|
||||
function ProfilerProxy(opts) {
|
||||
this.profile = !!opts.profile;
|
||||
|
||||
this.profiler = null;
|
||||
if (!!opts.profile) {
|
||||
this.profiler = new Profiler({statsd_client: opts.statsd_client});
|
||||
}
|
||||
}
|
||||
|
||||
ProfilerProxy.prototype.done = function(what) {
|
||||
if (this.profile) {
|
||||
this.profiler.done(what);
|
||||
}
|
||||
};
|
||||
|
||||
ProfilerProxy.prototype.end = function() {
|
||||
if (this.profile) {
|
||||
this.profiler.end();
|
||||
}
|
||||
};
|
||||
|
||||
ProfilerProxy.prototype.start = function(what) {
|
||||
if (this.profile) {
|
||||
this.profiler.start(what);
|
||||
}
|
||||
};
|
||||
|
||||
ProfilerProxy.prototype.add = function(what) {
|
||||
if (this.profile) {
|
||||
this.profiler.add(what || {});
|
||||
}
|
||||
};
|
||||
|
||||
ProfilerProxy.prototype.sendStats = function() {
|
||||
if (this.profile) {
|
||||
this.profiler.sendStats();
|
||||
}
|
||||
};
|
||||
|
||||
ProfilerProxy.prototype.toString = function() {
|
||||
return this.profile ? this.profiler.toString() : "";
|
||||
};
|
||||
|
||||
ProfilerProxy.prototype.toJSONString = function() {
|
||||
return this.profile ? this.profiler.toJSONString() : "{}";
|
||||
};
|
||||
|
||||
module.exports = ProfilerProxy;
|
||||
@@ -0,0 +1,70 @@
|
||||
// - Reports stats about:
|
||||
// * Total number of renderers
|
||||
// * For mapnik renderers:
|
||||
// - the mapnik-pool status: count, unused and waiting
|
||||
// - the internally cached objects: png and grid
|
||||
|
||||
var _ = require('underscore');
|
||||
|
||||
function RendererStatsReporter(rendererCache, statsInterval) {
|
||||
this.rendererCache = rendererCache;
|
||||
this.statsInterval = statsInterval || 6e4;
|
||||
this.renderersStatsIntervalId = null;
|
||||
}
|
||||
|
||||
module.exports = RendererStatsReporter;
|
||||
|
||||
RendererStatsReporter.prototype.start = function() {
|
||||
var self = this;
|
||||
this.renderersStatsIntervalId = setInterval(function() {
|
||||
var rendererCacheEntries = self.rendererCache.renderers;
|
||||
|
||||
if (!rendererCacheEntries) {
|
||||
return null;
|
||||
}
|
||||
|
||||
global.statsClient.gauge('windshaft.rendercache.count', _.keys(rendererCacheEntries).length);
|
||||
|
||||
var renderersStats = _.reduce(rendererCacheEntries, function(_rendererStats, cacheEntry) {
|
||||
var stats = cacheEntry.renderer && cacheEntry.renderer.getStats && cacheEntry.renderer.getStats();
|
||||
if (!stats) {
|
||||
return _rendererStats;
|
||||
}
|
||||
|
||||
_rendererStats.pool.count += stats.pool.count;
|
||||
_rendererStats.pool.unused += stats.pool.unused;
|
||||
_rendererStats.pool.waiting += stats.pool.waiting;
|
||||
|
||||
_rendererStats.cache.grid += stats.cache.grid;
|
||||
_rendererStats.cache.png += stats.cache.png;
|
||||
|
||||
return _rendererStats;
|
||||
},
|
||||
{
|
||||
pool: {
|
||||
count: 0,
|
||||
unused: 0,
|
||||
waiting: 0
|
||||
},
|
||||
cache: {
|
||||
png: 0,
|
||||
grid: 0
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
global.statsClient.gauge('windshaft.mapnik-cache.png', renderersStats.cache.png);
|
||||
global.statsClient.gauge('windshaft.mapnik-cache.grid', renderersStats.cache.grid);
|
||||
|
||||
global.statsClient.gauge('windshaft.mapnik-pool.count', renderersStats.pool.count);
|
||||
global.statsClient.gauge('windshaft.mapnik-pool.unused', renderersStats.pool.unused);
|
||||
global.statsClient.gauge('windshaft.mapnik-pool.waiting', renderersStats.pool.waiting);
|
||||
}, this.statsInterval);
|
||||
|
||||
};
|
||||
|
||||
|
||||
RendererStatsReporter.prototype.stop = function() {
|
||||
clearInterval(this.renderersStatsIntervalId);
|
||||
this.renderersStatsIntervalId = null;
|
||||
};
|
||||
Generated
+30
-30
@@ -66,6 +66,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.2.0",
|
||||
"from": "debug@~2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "0.7.1",
|
||||
"from": "ms@0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dot": {
|
||||
"version": "1.0.3",
|
||||
"from": "dot@~1.0.2",
|
||||
@@ -140,9 +152,9 @@
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.3",
|
||||
"from": "process-nextick-args@~1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.2.tgz"
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz"
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
@@ -255,9 +267,9 @@
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz",
|
||||
"dependencies": {
|
||||
"hoek": {
|
||||
"version": "2.14.0",
|
||||
"version": "2.15.0",
|
||||
"from": "hoek@2.x.x",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.14.0.tgz"
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.15.0.tgz"
|
||||
},
|
||||
"boom": {
|
||||
"version": "2.8.0",
|
||||
@@ -265,9 +277,9 @@
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-2.8.0.tgz"
|
||||
},
|
||||
"cryptiles": {
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.5",
|
||||
"from": "cryptiles@2.x.x",
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.4.tgz"
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
|
||||
},
|
||||
"sntp": {
|
||||
"version": "1.0.9",
|
||||
@@ -309,9 +321,9 @@
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-1.8.0.tgz",
|
||||
"dependencies": {
|
||||
"bluebird": {
|
||||
"version": "2.9.34",
|
||||
"version": "2.10.0",
|
||||
"from": "bluebird@^2.9.30",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.34.tgz"
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.0.tgz"
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.1",
|
||||
@@ -470,6 +482,11 @@
|
||||
"from": "lzma@~1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/lzma/-/lzma-1.3.7.tgz"
|
||||
},
|
||||
"node-statsd": {
|
||||
"version": "0.0.7",
|
||||
"from": "node-statsd@~0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/node-statsd/-/node-statsd-0.0.7.tgz"
|
||||
},
|
||||
"queue-async": {
|
||||
"version": "1.0.7",
|
||||
"from": "queue-async@~1.0.7",
|
||||
@@ -518,6 +535,11 @@
|
||||
"from": "step@~0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/step/-/step-0.0.6.tgz"
|
||||
},
|
||||
"step-profiler": {
|
||||
"version": "0.2.1",
|
||||
"from": "step-profiler@~0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/step-profiler/-/step-profiler-0.2.1.tgz"
|
||||
},
|
||||
"underscore": {
|
||||
"version": "1.6.0",
|
||||
"from": "underscore@~1.6.0",
|
||||
@@ -2287,18 +2309,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.2.0",
|
||||
"from": "debug@~2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "0.7.1",
|
||||
"from": "ms@0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tilelive": {
|
||||
"version": "4.5.3",
|
||||
"from": "tilelive@~4.5.3",
|
||||
@@ -2766,11 +2776,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"step-profiler": {
|
||||
"version": "0.2.1",
|
||||
"from": "step-profiler@~0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/step-profiler/-/step-profiler-0.2.1.tgz"
|
||||
},
|
||||
"torque.js": {
|
||||
"version": "2.11.0",
|
||||
"from": "torque.js@~2.11.0",
|
||||
@@ -2959,11 +2964,6 @@
|
||||
"version": "1.0.2",
|
||||
"from": "sphericalmercator@1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/sphericalmercator/-/sphericalmercator-1.0.2.tgz"
|
||||
},
|
||||
"node-statsd": {
|
||||
"version": "0.0.7",
|
||||
"from": "node-statsd@~0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/node-statsd/-/node-statsd-0.0.7.tgz"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"express": "~2.5.11",
|
||||
"debug": "~2.2.0",
|
||||
"step-profiler": "~0.2.1",
|
||||
"node-statsd": "~0.0.7",
|
||||
"underscore" : "~1.6.0",
|
||||
"dot": "~1.0.2",
|
||||
"windshaft": "https://github.com/CartoDB/Windshaft/tarball/backend-foundations",
|
||||
|
||||
@@ -3,7 +3,7 @@ require('../../../support/test_helper.js');
|
||||
var assert = require('assert');
|
||||
var cartodbServer = require('../../../../lib/cartodb/server');
|
||||
var serverOptions = require('../../../../lib/cartodb/server_options');
|
||||
var StatsClient = require('windshaft').stats.Client;
|
||||
var StatsClient = require('../../../../lib/cartodb/stats/client');
|
||||
|
||||
var LayergroupController = require('../../../../lib/cartodb/controllers/layergroup');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user