UNPKG

unleash-server

Version:

Unleash is an enterprise ready feature toggles service. It provides different strategies for handling feature toggles.

130 lines • 5.89 kB
"use strict"; 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