2021-10-08 10:09:22 +02:00
|
|
|
import { Request, Response } from 'express';
|
2024-01-17 09:14:31 +01:00
|
|
|
import Controller from '../../../routes/controller';
|
|
|
|
import { IUnleashConfig } from '../../../types/option';
|
|
|
|
import { IFlagResolver, IUnleashServices } from '../../../types';
|
|
|
|
import { Logger } from '../../../logger';
|
|
|
|
import ClientMetricsServiceV2 from './metrics-service-v2';
|
|
|
|
import { NONE } from '../../../types/permissions';
|
|
|
|
import { createResponseSchema } from '../../../openapi/util/create-response-schema';
|
|
|
|
import { OpenApiService } from '../../../services/openapi-service';
|
|
|
|
import { serializeDates } from '../../../types/serialize-dates';
|
2022-06-27 10:17:44 +02:00
|
|
|
import {
|
|
|
|
FeatureUsageSchema,
|
|
|
|
featureUsageSchema,
|
2024-01-17 09:14:31 +01:00
|
|
|
} from '../../../openapi/spec/feature-usage-schema';
|
2022-06-27 10:17:44 +02:00
|
|
|
import {
|
|
|
|
featureMetricsSchema,
|
|
|
|
FeatureMetricsSchema,
|
2024-01-17 09:14:31 +01:00
|
|
|
} from '../../../openapi/spec/feature-metrics-schema';
|
|
|
|
import { getStandardResponses } from '../../../openapi';
|
2022-06-27 10:17:44 +02:00
|
|
|
|
|
|
|
interface IName {
|
|
|
|
name: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface IHoursBack {
|
|
|
|
hoursBack: number;
|
|
|
|
}
|
2021-10-08 10:09:22 +02:00
|
|
|
|
|
|
|
class ClientMetricsController extends Controller {
|
|
|
|
private logger: Logger;
|
|
|
|
|
|
|
|
private metrics: ClientMetricsServiceV2;
|
|
|
|
|
2022-06-27 10:17:44 +02:00
|
|
|
private openApiService: OpenApiService;
|
|
|
|
|
2024-01-11 10:39:41 +01:00
|
|
|
private flagResolver: Pick<IFlagResolver, 'isEnabled'>;
|
|
|
|
|
2022-02-17 10:47:05 +01:00
|
|
|
private static HOURS_BACK_MIN = 1;
|
|
|
|
|
|
|
|
private static HOURS_BACK_MAX = 48;
|
|
|
|
|
2024-01-11 10:39:41 +01:00
|
|
|
private static HOURS_BACK_MAX_V2 = 24 * 31 * 3; // 3 months
|
|
|
|
|
2021-10-08 10:09:22 +02:00
|
|
|
constructor(
|
|
|
|
config: IUnleashConfig,
|
|
|
|
{
|
|
|
|
clientMetricsServiceV2,
|
2022-06-27 10:17:44 +02:00
|
|
|
openApiService,
|
|
|
|
}: Pick<IUnleashServices, 'clientMetricsServiceV2' | 'openApiService'>,
|
2021-10-08 10:09:22 +02:00
|
|
|
) {
|
|
|
|
super(config);
|
|
|
|
this.logger = config.getLogger('/admin-api/client-metrics.ts');
|
|
|
|
|
|
|
|
this.metrics = clientMetricsServiceV2;
|
2022-06-27 10:17:44 +02:00
|
|
|
this.openApiService = openApiService;
|
2024-01-11 10:39:41 +01:00
|
|
|
this.flagResolver = config.flagResolver;
|
2022-06-27 10:17:44 +02:00
|
|
|
|
|
|
|
this.route({
|
|
|
|
method: 'get',
|
|
|
|
path: '/features/:name/raw',
|
|
|
|
handler: this.getRawToggleMetrics,
|
|
|
|
permission: NONE,
|
|
|
|
middleware: [
|
|
|
|
openApiService.validPath({
|
|
|
|
operationId: 'getRawFeatureMetrics',
|
2022-08-12 11:37:57 +02:00
|
|
|
tags: ['Metrics'],
|
2023-08-01 15:58:15 +02:00
|
|
|
summary: 'Get feature metrics',
|
|
|
|
description:
|
|
|
|
'Get usage metrics for a specific feature for the last 48 hours, grouped by hour',
|
2022-06-27 10:17:44 +02:00
|
|
|
responses: {
|
|
|
|
200: createResponseSchema('featureMetricsSchema'),
|
2023-04-26 12:10:57 +02:00
|
|
|
...getStandardResponses(401, 403, 404),
|
2022-06-27 10:17:44 +02:00
|
|
|
},
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
});
|
2021-10-08 10:09:22 +02:00
|
|
|
|
2022-06-27 10:17:44 +02:00
|
|
|
this.route({
|
|
|
|
method: 'get',
|
|
|
|
path: '/features/:name',
|
|
|
|
handler: this.getToggleMetricsSummary,
|
|
|
|
permission: NONE,
|
|
|
|
middleware: [
|
|
|
|
openApiService.validPath({
|
|
|
|
operationId: 'getFeatureUsageSummary',
|
2022-08-12 11:37:57 +02:00
|
|
|
tags: ['Metrics'],
|
2023-04-26 12:10:57 +02:00
|
|
|
summary: `Last hour of usage and a list of applications that have reported seeing this feature toggle`,
|
|
|
|
description:
|
|
|
|
'Separate counts for yes (enabled), no (disabled), as well as how many times each variant was selected during the last hour',
|
2022-06-27 10:17:44 +02:00
|
|
|
responses: {
|
|
|
|
200: createResponseSchema('featureUsageSchema'),
|
2023-04-26 12:10:57 +02:00
|
|
|
...getStandardResponses(401, 403, 404),
|
2022-06-27 10:17:44 +02:00
|
|
|
},
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
});
|
2021-10-08 10:09:22 +02:00
|
|
|
}
|
|
|
|
|
2022-06-27 10:17:44 +02:00
|
|
|
async getRawToggleMetrics(
|
|
|
|
req: Request<any, IName, IHoursBack, any>,
|
|
|
|
res: Response<FeatureMetricsSchema>,
|
|
|
|
): Promise<void> {
|
2021-10-08 10:09:22 +02:00
|
|
|
const { name } = req.params;
|
2022-02-17 10:47:05 +01:00
|
|
|
const { hoursBack } = req.query;
|
|
|
|
const data = await this.metrics.getClientMetricsForToggle(
|
|
|
|
name,
|
|
|
|
this.parseHoursBackQueryParam(hoursBack),
|
|
|
|
);
|
2022-06-27 10:17:44 +02:00
|
|
|
this.openApiService.respondWithValidation(
|
|
|
|
200,
|
|
|
|
res,
|
|
|
|
featureMetricsSchema.$id,
|
|
|
|
{ version: 1, maturity: 'stable', data: serializeDates(data) },
|
|
|
|
);
|
2021-10-08 10:09:22 +02:00
|
|
|
}
|
|
|
|
|
2022-06-27 10:17:44 +02:00
|
|
|
async getToggleMetricsSummary(
|
|
|
|
req: Request<IName>,
|
|
|
|
res: Response<FeatureUsageSchema>,
|
|
|
|
): Promise<void> {
|
2021-10-08 10:09:22 +02:00
|
|
|
const { name } = req.params;
|
|
|
|
const data = await this.metrics.getFeatureToggleMetricsSummary(name);
|
2022-06-27 10:17:44 +02:00
|
|
|
|
|
|
|
this.openApiService.respondWithValidation(
|
|
|
|
200,
|
|
|
|
res,
|
|
|
|
featureUsageSchema.$id,
|
|
|
|
{ version: 1, maturity: 'stable', ...serializeDates(data) },
|
|
|
|
);
|
2021-10-08 10:09:22 +02:00
|
|
|
}
|
2022-02-17 10:47:05 +01:00
|
|
|
|
|
|
|
private parseHoursBackQueryParam(param: unknown): number | undefined {
|
|
|
|
if (typeof param !== 'string') {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
const parsed = Number(param);
|
2024-01-11 10:39:41 +01:00
|
|
|
const max = this.flagResolver.isEnabled('extendedUsageMetrics')
|
|
|
|
? ClientMetricsController.HOURS_BACK_MAX_V2
|
|
|
|
: ClientMetricsController.HOURS_BACK_MAX;
|
2022-02-17 10:47:05 +01:00
|
|
|
|
2024-01-11 10:39:41 +01:00
|
|
|
if (parsed >= ClientMetricsController.HOURS_BACK_MIN && parsed <= max) {
|
2022-02-17 10:47:05 +01:00
|
|
|
return parsed;
|
|
|
|
}
|
|
|
|
}
|
2021-10-08 10:09:22 +02:00
|
|
|
}
|
2022-02-17 10:47:05 +01:00
|
|
|
|
2021-10-08 10:09:22 +02:00
|
|
|
export default ClientMetricsController;
|