diff --git a/src/lib/db/client-metrics-store-v2.test.ts b/src/lib/db/client-metrics-store-v2.test.ts index e4c3b2a050..95bb8fc1e3 100644 --- a/src/lib/db/client-metrics-store-v2.test.ts +++ b/src/lib/db/client-metrics-store-v2.test.ts @@ -216,7 +216,7 @@ test('count previous day metrics', async () => { }, ]); - const result = await clientMetricsStore.countPreviousDayMetrics(); + const result = await clientMetricsStore.countPreviousDayMetricsBuckets(); expect(result).toMatchObject({ enabledCount: 2, variantCount: 4 }); }); diff --git a/src/lib/db/client-metrics-store-v2.ts b/src/lib/db/client-metrics-store-v2.ts index fdb537a9b7..d009a0e8bf 100644 --- a/src/lib/db/client-metrics-store-v2.ts +++ b/src/lib/db/client-metrics-store-v2.ts @@ -339,7 +339,7 @@ export class ClientMetricsStoreV2 implements IClientMetricsStoreV2 { .del(); } - async countPreviousDayMetrics(): Promise<{ + async countPreviousDayMetricsBuckets(): Promise<{ enabledCount: number; variantCount: number; }> { diff --git a/src/lib/features/instance-stats/instance-stats-service.ts b/src/lib/features/instance-stats/instance-stats-service.ts index ea94956989..86c5367a01 100644 --- a/src/lib/features/instance-stats/instance-stats-service.ts +++ b/src/lib/features/instance-stats/instance-stats-service.ts @@ -3,6 +3,7 @@ import { Logger } from '../../logger'; import { IUnleashConfig } from '../../types/option'; import { IClientInstanceStore, + IClientMetricsStoreV2, IEventStore, IUnleashStores, } from '../../types/stores'; @@ -54,6 +55,10 @@ export interface InstanceStats { clientApps: { range: TimeRange; count: number }[]; activeUsers: Awaited>; productionChanges: Awaited>; + previousDayMetricsBucketsCount: { + enabledCount: number; + variantCount: number; + }; } export type InstanceStatsSigned = Omit & { @@ -92,6 +97,8 @@ export class InstanceStatsService { private clientInstanceStore: IClientInstanceStore; + private clientMetricsStore: IClientMetricsStoreV2; + private snapshot?: InstanceStats; private appCount?: Partial<{ [key in TimeRange]: number }>; @@ -115,6 +122,7 @@ export class InstanceStatsService { clientInstanceStore, eventStore, apiTokenStore, + clientMetricsStoreV2, }: Pick< IUnleashStores, | 'featureToggleStore' @@ -130,6 +138,7 @@ export class InstanceStatsService { | 'clientInstanceStore' | 'eventStore' | 'apiTokenStore' + | 'clientMetricsStoreV2' >, { getLogger }: Pick, versionService: VersionService, @@ -153,6 +162,7 @@ export class InstanceStatsService { this.getActiveUsers = getActiveUsers; this.getProductionChanges = getProductionChanges; this.apiTokenStore = apiTokenStore; + this.clientMetricsStore = clientMetricsStoreV2; } async refreshStatsSnapshot(): Promise { @@ -223,6 +233,7 @@ export class InstanceStatsService { featureExports, featureImports, productionChanges, + previousDayMetricsBucketsCount, ] = await Promise.all([ this.getToggleCount(), this.userStore.count(), @@ -244,6 +255,7 @@ export class InstanceStatsService { this.eventStore.filteredCount({ type: FEATURES_EXPORTED }), this.eventStore.filteredCount({ type: FEATURES_IMPORTED }), this.getProductionChanges(), + this.clientMetricsStore.countPreviousDayMetricsBuckets(), ]); return { @@ -271,6 +283,7 @@ export class InstanceStatsService { featureExports, featureImports, productionChanges, + previousDayMetricsBucketsCount, }; } diff --git a/src/lib/metrics.ts b/src/lib/metrics.ts index a807996309..7ccaf78184 100644 --- a/src/lib/metrics.ts +++ b/src/lib/metrics.ts @@ -112,6 +112,14 @@ export default class MetricsMonitor { help: 'Number of API tokens', labelNames: ['type'], }); + const enabledMetricsBucketsPreviousDay = new client.Gauge({ + name: 'enabled_metrics_buckets_previous_day', + help: 'Number of hourly enabled/disabled metric buckets in the previous day', + }); + const variantMetricsBucketsPreviousDay = new client.Gauge({ + name: 'variant_metrics_buckets_previous_day', + help: 'Number of hourly variant metric buckets in the previous day', + }); const usersActive7days = new client.Gauge({ name: 'users_active_7', help: 'Number of users active in the last 7 days', @@ -235,6 +243,15 @@ export default class MetricsMonitor { apiTokens.labels(type).set(value); } + enabledMetricsBucketsPreviousDay.reset(); + enabledMetricsBucketsPreviousDay.set( + stats.previousDayMetricsBucketsCount.enabledCount, + ); + variantMetricsBucketsPreviousDay.reset(); + variantMetricsBucketsPreviousDay.set( + stats.previousDayMetricsBucketsCount.variantCount, + ); + usersActive7days.reset(); usersActive7days.set(stats.activeUsers.last7); usersActive30days.reset(); diff --git a/src/lib/openapi/spec/instance-admin-stats-schema.ts b/src/lib/openapi/spec/instance-admin-stats-schema.ts index 4105051eb6..d58f142189 100644 --- a/src/lib/openapi/spec/instance-admin-stats-schema.ts +++ b/src/lib/openapi/spec/instance-admin-stats-schema.ts @@ -39,6 +39,27 @@ export const instanceAdminStatsSchema = { example: 8, minimum: 0, }, + previousDayMetricsBucketsCount: { + type: 'object', + description: + 'The number client metrics buckets records recorded in the previous day. # features * # apps * # envs * # hours with metrics', + properties: { + enabledCount: { + type: 'number', + description: + 'The number of enabled/disabled metrics buckets recorded in the previous day', + example: 10, + minimum: 0, + }, + variantCount: { + type: 'number', + description: + 'The number of variant metrics buckets recorded in the previous day', + example: 10, + minimum: 0, + }, + }, + }, activeUsers: { type: 'object', description: diff --git a/src/lib/routes/admin-api/instance-admin.ts b/src/lib/routes/admin-api/instance-admin.ts index b8c8457bb8..be6f6ae2d9 100644 --- a/src/lib/routes/admin-api/instance-admin.ts +++ b/src/lib/routes/admin-api/instance-admin.ts @@ -120,6 +120,10 @@ class InstanceAdminController extends Controller { last60: 200, last90: 200, }, + previousDayMetricsBucketsCount: { + variantCount: 100, + enabledCount: 200, + }, }; } diff --git a/src/lib/services/client-metrics/metrics-service-v2.test.ts b/src/lib/services/client-metrics/metrics-service-v2.test.ts index b414bb2ebf..52ea16b7ea 100644 --- a/src/lib/services/client-metrics/metrics-service-v2.test.ts +++ b/src/lib/services/client-metrics/metrics-service-v2.test.ts @@ -246,7 +246,7 @@ test('aggregate previous day metrics when metrics count is below limit', async ( aggregationCalled = true; return Promise.resolve(); }, - countPreviousDayMetrics() { + countPreviousDayMetricsBuckets() { return { enabledCount, variantCount }; }, } as unknown as IClientMetricsStoreV2; diff --git a/src/lib/services/client-metrics/metrics-service-v2.ts b/src/lib/services/client-metrics/metrics-service-v2.ts index e3a8910d5c..f230d62158 100644 --- a/src/lib/services/client-metrics/metrics-service-v2.ts +++ b/src/lib/services/client-metrics/metrics-service-v2.ts @@ -62,7 +62,7 @@ export default class ClientMetricsServiceV2 { async aggregateDailyMetrics() { if (this.flagResolver.isEnabled('extendedUsageMetrics')) { const { enabledCount, variantCount } = - await this.clientMetricsStoreV2.countPreviousDayMetrics(); + await this.clientMetricsStoreV2.countPreviousDayMetricsBuckets(); const { payload } = this.flagResolver.getVariant( 'extendedUsageMetrics', ); diff --git a/src/lib/types/stores/client-metrics-store-v2.ts b/src/lib/types/stores/client-metrics-store-v2.ts index 8d0d70f264..8f502245bf 100644 --- a/src/lib/types/stores/client-metrics-store-v2.ts +++ b/src/lib/types/stores/client-metrics-store-v2.ts @@ -39,7 +39,7 @@ export interface IClientMetricsStoreV2 ): Promise; clearMetrics(hoursAgo: number): Promise; clearDailyMetrics(daysAgo: number): Promise; - countPreviousDayMetrics(): Promise<{ + countPreviousDayMetricsBuckets(): Promise<{ enabledCount: number; variantCount: number; }>; diff --git a/src/test/fixtures/fake-client-metrics-store-v2.ts b/src/test/fixtures/fake-client-metrics-store-v2.ts index c06eb0e9ed..eda83ca9e5 100644 --- a/src/test/fixtures/fake-client-metrics-store-v2.ts +++ b/src/test/fixtures/fake-client-metrics-store-v2.ts @@ -29,7 +29,7 @@ export default class FakeClientMetricsStoreV2 clearDailyMetrics(daysBack: number): Promise { return Promise.resolve(); } - countPreviousDayMetrics(): Promise<{ + countPreviousDayMetricsBuckets(): Promise<{ enabledCount: number; variantCount: number; }> {