diff --git a/packages/unleash-api/lib/client-metrics-service.js b/packages/unleash-api/lib/client-metrics-service.js new file mode 100644 index 0000000000..17eba77d8e --- /dev/null +++ b/packages/unleash-api/lib/client-metrics-service.js @@ -0,0 +1,34 @@ +'use strict'; +const POLL_INTERVAL = 10000; + +module.exports = class UnleashClientMetrics { + constructor (metricsDb) { + this.metricsDb = metricsDb; + this.metrics = []; + this.highestIdSeen = 0; + metricsDb.getMetricsLastWeek().then(metrics => { + this.addMetrics(metrics); + this.startPoller(); + }); + } + + addMetrics (metrics) { + metrics.forEach(m => this.metrics.push(m)); + this.highestIdSeen = this.metrics[this.metrics.length - 1].id; + } + + startPoller () { + setInterval(() => { + this.metricsDb.getNewMetrics(this.highestIdSeen) + .then(metrics => this.addMetrics(metrics)); + }, POLL_INTERVAL).unref(); + } + + getMetrics () { + return this.metrics; + } + + insert (metrics) { + this.metricsDb.insert(metrics).then(() => console.log('new metrics inserted!')); + } +}; diff --git a/packages/unleash-api/lib/db/metrics.js b/packages/unleash-api/lib/db/metrics.js new file mode 100644 index 0000000000..c1781673f2 --- /dev/null +++ b/packages/unleash-api/lib/db/metrics.js @@ -0,0 +1,41 @@ +'use strict'; + +const METRICS_COLUMNS = ['id', 'created_at', 'metrics']; +const TABLE = 'client_metrics'; + +module.exports = function (db) { + // Insert new client metrics + function insert (metrics) { + return db(TABLE).insert({ metrics }); + } + + // Used at startup to load all metrics last week into memory! + function getMetricsLastWeek () { + return db + .select(METRICS_COLUMNS) + .from(TABLE) + .whereRaw('created_at > now() - interval \'7 day\'') + .orderBy('created_at', 'asc') + .map(mapRow); + } + + // Used to poll for new metrics + function getNewMetrics (lastKnownId) { + return db + .select(METRICS_COLUMNS) + .from(TABLE) + .where('id', '>', lastKnownId) + .orderBy('created_at', 'asc') + .map(mapRow); + } + + function mapRow (row) { + return { + id: row.id, + createdAt: row.created_at, + metrics: row.metrics, + }; + } + + return { insert, getMetricsLastWeek, getNewMetrics }; +}; diff --git a/packages/unleash-api/lib/routes/metrics.js b/packages/unleash-api/lib/routes/metrics.js index 408444a6ea..6573540422 100644 --- a/packages/unleash-api/lib/routes/metrics.js +++ b/packages/unleash-api/lib/routes/metrics.js @@ -2,23 +2,36 @@ const logger = require('../logger'); const ClientMetrics = require('../client-metrics'); +const ClientMetricsService = require('../client-metrics-service'); -module.exports = function (app) { +module.exports = function (app, config) { + const metricsDb = config.metricsDb; const metrics = new ClientMetrics(); + const service = new ClientMetricsService(metricsDb); app.get('/metrics', (req, res) => { - res.json(metrics.getState()); + res.json(service.getMetrics()); + + // Your stuff: + // res.json(metrics.getState()); }); app.post('/metrics', (req, res) => { + // TODO: validate input and reply with http errorcode try { - const data = JSON.parse(req.body); - metrics.addPayload(data); + // not required with header: Content-Type: application/json + // const data = JSON.parse(req.body); + // metrics.addPayload(data); + service.insert(req.body); } catch (e) { logger.error('Error recieving metrics', e); } res.end(); }); + + app.get('/metrics', (req, res) => { + res.json(metrics.getState()); + }); }; diff --git a/packages/unleash-api/migrations/20161027134128-create-metrics.js b/packages/unleash-api/migrations/20161027134128-create-metrics.js new file mode 100644 index 0000000000..cc43e6f405 --- /dev/null +++ b/packages/unleash-api/migrations/20161027134128-create-metrics.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('../scripts/migration-runner').create('008-create-metrics'); diff --git a/packages/unleash-api/migrations/sql/008-create-metrics.down.sql b/packages/unleash-api/migrations/sql/008-create-metrics.down.sql new file mode 100644 index 0000000000..88a3e5a53e --- /dev/null +++ b/packages/unleash-api/migrations/sql/008-create-metrics.down.sql @@ -0,0 +1,2 @@ +--drop new metrics table +DROP TABLE client_metrics; \ No newline at end of file diff --git a/packages/unleash-api/migrations/sql/008-create-metrics.up.sql b/packages/unleash-api/migrations/sql/008-create-metrics.up.sql new file mode 100644 index 0000000000..7b0d95f3f3 --- /dev/null +++ b/packages/unleash-api/migrations/sql/008-create-metrics.up.sql @@ -0,0 +1,6 @@ +--create new metrics table +CREATE TABLE client_metrics ( + id serial primary key, + created_at timestamp default now(), + metrics json +); \ No newline at end of file diff --git a/packages/unleash-api/server-impl.js b/packages/unleash-api/server-impl.js index 0cb19b964c..ef18610da8 100644 --- a/packages/unleash-api/server-impl.js +++ b/packages/unleash-api/server-impl.js @@ -18,6 +18,7 @@ function createApp (options) { const eventStore = new EventStore(eventDb); const featureDb = require('./lib/db/feature')(db, eventStore); const strategyDb = require('./lib/db/strategy')(db, eventStore); + const metricsDb = require('./lib/db/metrics')(db); const config = { baseUriPath: options.baseUriPath, @@ -28,6 +29,7 @@ function createApp (options) { eventStore, featureDb, strategyDb, + metricsDb, }; const app = require('./app')(config);