mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-24 01:18:01 +02:00
Some Metrics API cleanups
This commit is contained in:
parent
f7a89b8223
commit
84e0810d64
@ -96,7 +96,7 @@ will in most cases remember seen-toggles for applications longer
|
|||||||
|
|
||||||
### Feature-Toggles metrics
|
### Feature-Toggles metrics
|
||||||
|
|
||||||
`GET http://unleash.host.com/api/metrics/feature-toggles`
|
`GET http://unleash.host.com/api/client/metrics/feature-toggles`
|
||||||
|
|
||||||
This endpoint gives _last minute_ and _last hour_ metrics for all active toggles. This is based on
|
This endpoint gives _last minute_ and _last hour_ metrics for all active toggles. This is based on
|
||||||
metrics reported by client applications. Yes is the number of times a given feature toggle
|
metrics reported by client applications. Yes is the number of times a given feature toggle
|
||||||
|
@ -5,13 +5,8 @@ const ClientMetrics = require('../client-metrics');
|
|||||||
const joi = require('joi');
|
const joi = require('joi');
|
||||||
const { clientMetricsSchema, clientRegisterSchema } = require('./metrics-schema');
|
const { clientMetricsSchema, clientRegisterSchema } = require('./metrics-schema');
|
||||||
const { CLIENT_REGISTER, CLIENT_METRICS } = require('../events');
|
const { CLIENT_REGISTER, CLIENT_METRICS } = require('../events');
|
||||||
/*
|
const { catchLogAndSendErrorResponse } = require('./route-utils');
|
||||||
* TODO:
|
|
||||||
* - always catch errors and always return a response to client!
|
|
||||||
* - clean up and document uri endpoint
|
|
||||||
* - always json response (middleware?)
|
|
||||||
* - fix failing tests
|
|
||||||
*/
|
|
||||||
module.exports = function (app, config) {
|
module.exports = function (app, config) {
|
||||||
const {
|
const {
|
||||||
clientMetricsStore,
|
clientMetricsStore,
|
||||||
@ -28,7 +23,7 @@ module.exports = function (app, config) {
|
|||||||
res.json(seenAppToggles);
|
res.json(seenAppToggles);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/metrics/feature-toggles', (req, res) => {
|
app.get('/client/metrics/feature-toggles', (req, res) => {
|
||||||
res.json(metrics.getTogglesMetrics());
|
res.json(metrics.getTogglesMetrics());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,7 +45,7 @@ module.exports = function (app, config) {
|
|||||||
instanceId: cleaned.instanceId,
|
instanceId: cleaned.instanceId,
|
||||||
clientIp,
|
clientIp,
|
||||||
}))
|
}))
|
||||||
.catch(e => logger.error('Error inserting metrics data', e));
|
.catch(err => catchLogAndSendErrorResponse(err, res));
|
||||||
|
|
||||||
res.status(202).end();
|
res.status(202).end();
|
||||||
});
|
});
|
||||||
@ -74,8 +69,9 @@ module.exports = function (app, config) {
|
|||||||
instanceId: cleaned.instanceId,
|
instanceId: cleaned.instanceId,
|
||||||
clientIp,
|
clientIp,
|
||||||
}))
|
}))
|
||||||
.then(() => logger.info('New client registered!'))
|
.then(() => logger.info(`New client registered with
|
||||||
.catch((error) => logger.error('Error registering client', error));
|
appName=${cleaned.appName} and instanceId=${cleaned.instanceId}`))
|
||||||
|
.catch(err => catchLogAndSendErrorResponse(err, res));
|
||||||
|
|
||||||
res.status(202).end();
|
res.status(202).end();
|
||||||
});
|
});
|
||||||
@ -86,11 +82,11 @@ module.exports = function (app, config) {
|
|||||||
if(appName) {
|
if(appName) {
|
||||||
clientStrategyStore.getByAppName(appName)
|
clientStrategyStore.getByAppName(appName)
|
||||||
.then(data => res.json(data))
|
.then(data => res.json(data))
|
||||||
.catch(err => logger.error(err));
|
.catch(err => catchLogAndSendErrorResponse(err, res));
|
||||||
} else {
|
} else {
|
||||||
clientStrategyStore.getAll()
|
clientStrategyStore.getAll()
|
||||||
.then(data => res.json(data))
|
.then(data => res.json(data))
|
||||||
.catch(err => logger.error(err));
|
.catch(err => catchLogAndSendErrorResponse(err, res));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -105,7 +101,7 @@ module.exports = function (app, config) {
|
|||||||
}))
|
}))
|
||||||
res.json({applications})
|
res.json({applications})
|
||||||
})
|
})
|
||||||
.catch(err => logger.error(err));
|
.catch(err => catchLogAndSendErrorResponse(err, res));
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/client/applications/:appName', (req, res) => {
|
app.get('/client/applications/:appName', (req, res) => {
|
||||||
@ -116,6 +112,6 @@ module.exports = function (app, config) {
|
|||||||
clientStrategyStore.getByAppName(appName)
|
clientStrategyStore.getByAppName(appName)
|
||||||
])
|
])
|
||||||
.then(([instances, strategies]) => res.json({appName, instances, strategies, seenToggles}))
|
.then(([instances, strategies]) => res.json({appName, instances, strategies, seenToggles}))
|
||||||
.catch(err => logger.error(err));
|
.catch(err => catchLogAndSendErrorResponse(err, res));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
8
lib/routes/route-utils.js
Normal file
8
lib/routes/route-utils.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
const logger = require('../logger');
|
||||||
|
|
||||||
|
const catchLogAndSendErrorResponse = (err, res) => {
|
||||||
|
logger.error(err);
|
||||||
|
res.status(500).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { catchLogAndSendErrorResponse };
|
@ -2,4 +2,5 @@
|
|||||||
|
|
||||||
module.exports = () => ({
|
module.exports = () => ({
|
||||||
insert: () => Promise.resolve(),
|
insert: () => Promise.resolve(),
|
||||||
|
getApplications: () => Promise.resolve([]),
|
||||||
});
|
});
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
|
|
||||||
module.exports = () => ({
|
module.exports = () => ({
|
||||||
insert: () => Promise.resolve(),
|
insert: () => Promise.resolve(),
|
||||||
|
getAll: () => Promise.resolve([])
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = () => ({
|
const { EventEmitter } = require('events');
|
||||||
getMetricsLastHour: () => Promise.resolve([]),
|
|
||||||
insert: () => Promise.resolve(),
|
class FakeMetricsStore extends EventEmitter {
|
||||||
on: () => {}
|
getMetricsLastHour () {
|
||||||
});
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
insert () {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = FakeMetricsStore;
|
@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const clientMetricsStore = require('./fake-metrics-store');
|
const ClientMetricsStore = require('./fake-metrics-store');
|
||||||
const clientStrategyStore = require('./fake-client-strategy-store');
|
const clientStrategyStore = require('./fake-client-strategy-store');
|
||||||
const clientInstanceStore = require('./fake-client-instance-store');
|
const clientInstanceStore = require('./fake-client-instance-store');
|
||||||
const featureToggleStore = require('./fake-feature-toggle-store');
|
const featureToggleStore = require('./fake-feature-toggle-store');
|
||||||
@ -19,7 +19,7 @@ module.exports = {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
db,
|
db,
|
||||||
clientMetricsStore: clientMetricsStore(),
|
clientMetricsStore: new ClientMetricsStore(),
|
||||||
clientStrategyStore: clientStrategyStore(),
|
clientStrategyStore: clientStrategyStore(),
|
||||||
clientInstanceStore: clientInstanceStore(),
|
clientInstanceStore: clientInstanceStore(),
|
||||||
featureToggleStore: featureToggleStore(),
|
featureToggleStore: featureToggleStore(),
|
||||||
|
@ -23,6 +23,7 @@ function getSetup () {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
request: supertest(app),
|
request: supertest(app),
|
||||||
|
stores
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,3 +78,95 @@ test('should accept client metrics', () => {
|
|||||||
})
|
})
|
||||||
.expect(202);
|
.expect(202);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should return seen toggles even when there is nothing', t => {
|
||||||
|
const { request } = getSetup();
|
||||||
|
return request
|
||||||
|
.get('/api/client/seen-toggles')
|
||||||
|
.expect(200)
|
||||||
|
.expect((res) => {
|
||||||
|
t.true(res.body.length === 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return list of seen-toggles per app', t => {
|
||||||
|
const { request, stores } = getSetup();
|
||||||
|
const appName = 'asd!23'
|
||||||
|
stores.clientMetricsStore.emit('metrics', {
|
||||||
|
appName,
|
||||||
|
instanceId: 'instanceId',
|
||||||
|
bucket: {
|
||||||
|
start: new Date(),
|
||||||
|
stop: new Date(),
|
||||||
|
toggles: {
|
||||||
|
toggleX: {yes: 123,no: 0},
|
||||||
|
toggleY: {yes: 123,no: 0}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return request
|
||||||
|
.get('/api/client/seen-toggles')
|
||||||
|
.expect(200)
|
||||||
|
.expect((res) => {
|
||||||
|
const seenAppsWithToggles = res.body;
|
||||||
|
t.true(seenAppsWithToggles.length === 1);
|
||||||
|
t.true(seenAppsWithToggles[0].appName === appName);
|
||||||
|
t.true(seenAppsWithToggles[0].seenToggles.length === 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return feature-toggles metrics even when there is nothing', t => {
|
||||||
|
const { request } = getSetup();
|
||||||
|
return request
|
||||||
|
.get('/api/client/metrics/feature-toggles')
|
||||||
|
.expect(200)
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return metrics for all toggles', t => {
|
||||||
|
const { request, stores } = getSetup();
|
||||||
|
const appName = 'asd!23'
|
||||||
|
stores.clientMetricsStore.emit('metrics', {
|
||||||
|
appName,
|
||||||
|
instanceId: 'instanceId',
|
||||||
|
bucket: {
|
||||||
|
start: new Date(),
|
||||||
|
stop: new Date(),
|
||||||
|
toggles: {
|
||||||
|
toggleX: {yes: 123,no: 0},
|
||||||
|
toggleY: {yes: 123,no: 0}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return request
|
||||||
|
.get('/api/client/metrics/feature-toggles')
|
||||||
|
.expect(200)
|
||||||
|
.expect((res) => {
|
||||||
|
|
||||||
|
const metrics = res.body;
|
||||||
|
t.true(metrics.lastHour !== undefined);
|
||||||
|
t.true(metrics.lastMinute !== undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('should return list of client strategies', t => {
|
||||||
|
const { request, stores } = getSetup();
|
||||||
|
return request
|
||||||
|
.get('/api/client/strategies')
|
||||||
|
.expect(200)
|
||||||
|
.expect((res) => {
|
||||||
|
t.true(res.body.length === 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return list of client applications', t => {
|
||||||
|
const { request, stores } = getSetup();
|
||||||
|
return request
|
||||||
|
.get('/api/client/applications')
|
||||||
|
.expect(200)
|
||||||
|
.expect((res) => {
|
||||||
|
t.true(res.body.applications.length === 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user