unleash-server
Version:
Unleash is an enterprise ready feature toggles service. It provides different strategies for handling feature toggles.
130 lines • 5.89 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const schema_1 = require("./schema");
const date_fns_1 = require("date-fns");
const events_1 = require("../../types/events");
const api_user_1 = __importDefault(require("../../types/api-user"));
const api_token_1 = require("../../types/models/api-token");
const collapseHourlyMetrics_1 = require("../../util/collapseHourlyMetrics");
const time_utils_1 = require("../../util/time-utils");
class ClientMetricsServiceV2 {
constructor({ featureToggleStore, clientMetricsStoreV2, }, config, lastSeenService, bulkInterval = (0, date_fns_1.secondsToMilliseconds)(5)) {
this.timers = [];
this.unsavedMetrics = [];
this.featureToggleStore = featureToggleStore;
this.clientMetricsStoreV2 = clientMetricsStoreV2;
this.lastSeenService = lastSeenService;
this.config = config;
this.flagResolver = config.flagResolver;
this.logger = config.getLogger('/services/client-metrics/client-metrics-service-v2.ts');
this.timers.push(setInterval(() => {
this.bulkAdd().catch(console.error);
}, bulkInterval).unref());
this.timers.push(setInterval(() => {
this.clientMetricsStoreV2.clearMetrics(48).catch(console.error);
}, (0, date_fns_1.hoursToMilliseconds)(12)).unref());
}
async registerClientMetrics(data, clientIp) {
const value = await schema_1.clientMetricsSchema.validateAsync(data);
const toggleNames = Object.keys(value.bucket.toggles).filter((name) => !(value.bucket.toggles[name].yes === 0 &&
value.bucket.toggles[name].no === 0));
this.logger.debug(`got metrics from ${clientIp}`);
const clientMetrics = toggleNames.map((name) => ({
featureName: name,
appName: value.appName,
environment: value.environment,
timestamp: value.bucket.start,
yes: value.bucket.toggles[name].yes,
no: value.bucket.toggles[name].no,
}));
if (this.config.flagResolver.isEnabled('batchMetrics')) {
this.unsavedMetrics = (0, collapseHourlyMetrics_1.collapseHourlyMetrics)([
...this.unsavedMetrics,
...clientMetrics,
]);
this.lastSeenService.updateLastSeen(clientMetrics);
}
else {
if (toggleNames.length > 0) {
await this.featureToggleStore.setLastSeen(toggleNames);
}
await this.clientMetricsStoreV2.batchInsertMetrics(clientMetrics);
}
this.config.eventBus.emit(events_1.CLIENT_METRICS, value);
}
async bulkAdd() {
if (this.unsavedMetrics.length > 0) {
// Make a copy of `unsavedMetrics` in case new metrics
// arrive while awaiting `batchInsertMetrics`.
const copy = [...this.unsavedMetrics];
this.unsavedMetrics = [];
await this.clientMetricsStoreV2.batchInsertMetrics(copy);
}
}
// Overview over usage last "hour" bucket and all applications using the toggle
async getFeatureToggleMetricsSummary(featureName) {
const metrics = await this.clientMetricsStoreV2.getMetricsForFeatureToggle(featureName, 1);
const seenApplications = await this.clientMetricsStoreV2.getSeenAppsForFeatureToggle(featureName);
const groupedMetrics = metrics.reduce((prev, curr) => {
if (prev[curr.environment]) {
prev[curr.environment].yes += curr.yes;
prev[curr.environment].no += curr.no;
}
else {
prev[curr.environment] = {
environment: curr.environment,
timestamp: curr.timestamp,
yes: curr.yes,
no: curr.no,
};
}
return prev;
}, {});
return {
featureName,
lastHourUsage: Object.values(groupedMetrics),
seenApplications,
};
}
async getClientMetricsForToggle(featureName, hoursBack = 24) {
const metrics = await this.clientMetricsStoreV2.getMetricsForFeatureToggle(featureName, hoursBack);
const hours = (0, time_utils_1.generateHourBuckets)(hoursBack);
const environments = [...new Set(metrics.map((x) => x.environment))];
const applications = [...new Set(metrics.map((x) => x.appName))].slice(0, 100);
const result = environments.flatMap((environment) => applications.flatMap((appName) => hours.flatMap((hourBucket) => {
const metric = metrics.find((item) => (0, date_fns_1.compareAsc)(hourBucket.timestamp, item.timestamp) ===
0 &&
item.appName === appName &&
item.environment === environment);
return (metric || {
timestamp: hourBucket.timestamp,
no: 0,
yes: 0,
appName,
environment,
featureName,
});
})));
return result.sort((a, b) => (0, date_fns_1.compareAsc)(a.timestamp, b.timestamp));
}
resolveMetricsEnvironment(user, data) {
if (user instanceof api_user_1.default) {
if (user.environment !== api_token_1.ALL) {
return user.environment;
}
else if (user.environment === api_token_1.ALL && data.environment) {
return data.environment;
}
}
return 'default';
}
destroy() {
this.timers.forEach(clearInterval);
this.lastSeenService.destroy();
}
}
exports.default = ClientMetricsServiceV2;
//# sourceMappingURL=metrics-service-v2.js.map