2016-10-27 13:13:51 +02:00
|
|
|
'use strict';
|
|
|
|
|
2016-11-04 16:16:55 +01:00
|
|
|
const Projection = require('./projection.js');
|
|
|
|
const TTLList = require('./ttl-list.js');
|
|
|
|
|
2016-10-27 13:13:51 +02:00
|
|
|
module.exports = class UnleashClientMetrics {
|
2017-06-28 10:17:14 +02:00
|
|
|
constructor(clientMetricsStore) {
|
2016-10-27 13:13:51 +02:00
|
|
|
this.globalCount = 0;
|
2016-11-04 16:16:55 +01:00
|
|
|
this.apps = {};
|
|
|
|
|
2016-11-07 09:13:19 +01:00
|
|
|
this.lastHourProjection = new Projection();
|
|
|
|
this.lastMinuteProjection = new Projection();
|
|
|
|
|
|
|
|
this.lastHourList = new TTLList({
|
|
|
|
interval: 10000,
|
|
|
|
});
|
2016-11-28 17:11:11 +01:00
|
|
|
|
2016-11-07 09:13:19 +01:00
|
|
|
this.lastMinuteList = new TTLList({
|
|
|
|
interval: 10000,
|
|
|
|
expireType: 'minutes',
|
|
|
|
expireAmount: 1,
|
|
|
|
});
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
this.lastHourList.on('expire', toggles => {
|
2016-11-04 16:16:55 +01:00
|
|
|
Object.keys(toggles).forEach(toggleName => {
|
2017-06-28 10:17:14 +02:00
|
|
|
this.lastHourProjection.substract(
|
|
|
|
toggleName,
|
2017-08-04 11:24:58 +02:00
|
|
|
this.createCountObject(toggles[toggleName])
|
2017-06-28 10:17:14 +02:00
|
|
|
);
|
2016-11-07 09:13:19 +01:00
|
|
|
});
|
|
|
|
});
|
2017-06-28 10:17:14 +02:00
|
|
|
this.lastMinuteList.on('expire', toggles => {
|
2016-11-07 09:13:19 +01:00
|
|
|
Object.keys(toggles).forEach(toggleName => {
|
2017-06-28 10:17:14 +02:00
|
|
|
this.lastMinuteProjection.substract(
|
|
|
|
toggleName,
|
2017-08-04 11:24:58 +02:00
|
|
|
this.createCountObject(toggles[toggleName])
|
2017-06-28 10:17:14 +02:00
|
|
|
);
|
2016-11-04 16:16:55 +01:00
|
|
|
});
|
|
|
|
});
|
2017-06-28 10:17:14 +02:00
|
|
|
clientMetricsStore.on('metrics', m => this.addPayload(m));
|
2016-10-27 13:13:51 +02:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
getAppsWithToggles() {
|
2016-11-28 17:11:11 +01:00
|
|
|
const apps = [];
|
|
|
|
Object.keys(this.apps).forEach(appName => {
|
|
|
|
const seenToggles = Object.keys(this.apps[appName].seenToggles);
|
|
|
|
const metricsCount = this.apps[appName].count;
|
2016-12-04 14:09:37 +01:00
|
|
|
apps.push({ appName, seenToggles, metricsCount });
|
2016-11-28 17:11:11 +01:00
|
|
|
});
|
|
|
|
return apps;
|
2016-10-27 13:13:51 +02:00
|
|
|
}
|
2017-06-28 10:17:14 +02:00
|
|
|
getSeenTogglesByAppName(appName) {
|
|
|
|
return this.apps[appName]
|
|
|
|
? Object.keys(this.apps[appName].seenToggles)
|
|
|
|
: [];
|
2016-10-27 13:13:51 +02:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
getSeenAppsPerToggle() {
|
2016-12-05 13:53:53 +01:00
|
|
|
const toggles = {};
|
2016-12-05 13:27:08 +01:00
|
|
|
Object.keys(this.apps).forEach(appName => {
|
2017-11-11 08:43:08 +01:00
|
|
|
Object.keys(this.apps[appName].seenToggles).forEach(
|
|
|
|
seenToggleName => {
|
|
|
|
if (!toggles[seenToggleName]) {
|
|
|
|
toggles[seenToggleName] = [];
|
|
|
|
}
|
|
|
|
toggles[seenToggleName].push({ appName });
|
2016-12-05 13:53:53 +01:00
|
|
|
}
|
2017-11-11 08:43:08 +01:00
|
|
|
);
|
2016-12-05 13:27:08 +01:00
|
|
|
});
|
2016-12-05 13:53:53 +01:00
|
|
|
return toggles;
|
2016-12-05 13:27:08 +01:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
getTogglesMetrics() {
|
2016-11-07 09:13:19 +01:00
|
|
|
return {
|
|
|
|
lastHour: this.lastHourProjection.getProjection(),
|
|
|
|
lastMinute: this.lastMinuteProjection.getProjection(),
|
|
|
|
};
|
2016-11-04 16:16:55 +01:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
addPayload(data) {
|
2016-11-28 17:11:11 +01:00
|
|
|
const { appName, bucket } = data;
|
2016-12-04 14:09:37 +01:00
|
|
|
const app = this.getApp(appName);
|
|
|
|
this.addBucket(app, bucket);
|
2016-11-28 17:11:11 +01:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
getApp(appName) {
|
|
|
|
this.apps[appName] = this.apps[appName] || {
|
|
|
|
seenToggles: {},
|
|
|
|
count: 0,
|
|
|
|
};
|
2016-11-28 17:11:11 +01:00
|
|
|
return this.apps[appName];
|
2016-10-27 13:13:51 +02:00
|
|
|
}
|
|
|
|
|
2017-08-04 11:24:58 +02:00
|
|
|
createCountObject(entry) {
|
2019-01-25 13:05:25 +01:00
|
|
|
let yes = typeof entry.yes == 'number' ? entry.yes : 0;
|
|
|
|
let no = typeof entry.no == 'number' ? entry.no : 0;
|
|
|
|
|
|
|
|
if (entry.variants) {
|
|
|
|
Object.entries(entry.variants).forEach(([key, value]) => {
|
|
|
|
if (key === 'disabled') {
|
|
|
|
no += value;
|
|
|
|
} else {
|
|
|
|
yes += value;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-08-04 11:24:58 +02:00
|
|
|
return { yes, no };
|
|
|
|
}
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
addBucket(app, bucket) {
|
2016-10-27 13:13:51 +02:00
|
|
|
let count = 0;
|
2016-11-04 16:16:55 +01:00
|
|
|
// TODO stop should be createdAt
|
|
|
|
const { stop, toggles } = bucket;
|
2016-10-27 15:16:27 +02:00
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
const toggleNames = Object.keys(toggles);
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
toggleNames.forEach(n => {
|
2017-08-04 11:24:58 +02:00
|
|
|
const countObj = this.createCountObject(toggles[n]);
|
|
|
|
this.lastHourProjection.add(n, countObj);
|
|
|
|
this.lastMinuteProjection.add(n, countObj);
|
|
|
|
count += countObj.yes + countObj.no;
|
2016-10-27 13:13:51 +02:00
|
|
|
});
|
2016-11-04 16:16:55 +01:00
|
|
|
|
2016-11-07 09:13:19 +01:00
|
|
|
this.lastHourList.add(toggles, stop);
|
|
|
|
this.lastMinuteList.add(toggles, stop);
|
2016-11-04 16:16:55 +01:00
|
|
|
|
2016-11-28 17:11:11 +01:00
|
|
|
this.globalCount += count;
|
2016-12-27 21:03:50 +01:00
|
|
|
app.count += count;
|
2016-11-28 17:11:11 +01:00
|
|
|
this.addSeenToggles(app, toggleNames);
|
2016-10-27 13:13:51 +02:00
|
|
|
}
|
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
addSeenToggles(app, toggleNames) {
|
2016-12-04 14:09:37 +01:00
|
|
|
toggleNames.forEach(t => {
|
|
|
|
app.seenToggles[t] = true;
|
|
|
|
});
|
2016-10-27 13:13:51 +02:00
|
|
|
}
|
2016-11-13 18:14:29 +01:00
|
|
|
|
2017-06-28 10:17:14 +02:00
|
|
|
destroy() {
|
2016-11-13 18:14:29 +01:00
|
|
|
this.lastHourList.destroy();
|
|
|
|
this.lastMinuteList.destroy();
|
|
|
|
}
|
2016-10-27 13:13:51 +02:00
|
|
|
};
|