1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

feat: start exposing environment metrics from feature endpoint (#6986)

We want to start showing same donut that we do show in project page.
This is setting it up for UI.
This commit is contained in:
Jaanus Sellin 2024-05-07 09:32:46 +03:00 committed by GitHub
parent 07871e73e5
commit 77d5156eba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 84 additions and 5 deletions

View File

@ -373,11 +373,37 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
userId,
}: ILoadFeatureToggleWithEnvsParams): Promise<FeatureToggleWithEnvironment> {
const stopTimer = this.timer('getFeatureAdmin');
let query = this.db('features_view')
const query = this.db.with('metrics', (queryBuilder) => {
queryBuilder
.sum('yes as yes')
.sum('no as no')
.select(['client_metrics_env.environment'])
.from('client_metrics_env')
.where(
'client_metrics_env.timestamp',
'>=',
this.db.raw("NOW() - INTERVAL '1 hour'"),
)
.andWhere('client_metrics_env.feature_name', featureName)
.groupBy(['client_metrics_env.environment']);
});
query
.from('features_view')
.where('name', featureName)
.modify(FeatureToggleStore.filterByArchived, archived);
let selectColumns = ['features_view.*'] as (string | Raw<any>)[];
let selectColumns = ['features_view.*', 'yes', 'no'] as (
| string
| Raw<any>
)[];
// add metrics
query.leftJoin(
'metrics',
'metrics.environment',
'features_view.environment',
);
query.leftJoin('last_seen_at_metrics', function () {
this.on(
@ -390,13 +416,14 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
'features_view.name',
);
});
// Override feature view for now
selectColumns.push(
'last_seen_at_metrics.last_seen_at as env_last_seen_at',
);
if (userId) {
query = query.leftJoin(`favorite_features`, function () {
query.leftJoin(`favorite_features`, function () {
this.on(
'favorite_features.feature',
'features_view.name',
@ -409,7 +436,6 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
),
];
}
const rows = await query.select(selectColumns);
stopTimer();
@ -463,6 +489,8 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
acc.variants = Array.from(currentVariants.values());
env.enabled = r.enabled;
env.yes = Number(r.yes) || 0;
env.no = Number(r.no) || 0;
env.type = r.environment_type;
env.sortOrder = r.environment_sort_order;
if (!env.strategies) {

View File

@ -16,7 +16,7 @@ import {
FEATURE_STRATEGY_REMOVE,
} from '../../../types/events';
import ApiUser from '../../../types/api-user';
import { ApiTokenType } from '../../../types/models/api-token';
import { ApiTokenType, type IApiToken } from '../../../types/models/api-token';
import IncompatibleProjectError from '../../../error/incompatible-project-error';
import {
type IStrategyConfig,
@ -36,6 +36,7 @@ import { ForbiddenError } from '../../../error';
let app: IUnleashTest;
let db: ITestDb;
let defaultToken: IApiToken;
const sortOrderFirst = 0;
const sortOrderSecond = 10;
const TESTUSERID = 3333;
@ -103,6 +104,14 @@ beforeAll(async () => {
},
db.rawDatabase,
);
defaultToken =
await app.services.apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.CLIENT,
projects: ['default'],
environment: 'default',
tokenName: 'tester',
});
});
afterEach(async () => {
@ -3684,3 +3693,43 @@ test('should return correct data structure for /api/admin/features', async () =>
strategies: [],
});
});
test('can get evaluation metrics', async () => {
await app.createFeature('metric-feature');
const now = new Date();
await app.request
.post('/api/client/metrics')
.set('Authorization', defaultToken.secret)
.send({
appName: 'appName',
instanceId: 'instanceId',
bucket: {
start: now,
stop: now,
toggles: {
'metric-feature': {
yes: 123,
no: 321,
},
},
},
})
.expect(202);
await app.services.clientMetricsServiceV2.bulkAdd();
const { body } = await app.request.get(
'/api/admin/projects/default/features/metric-feature',
);
expect(body).toMatchObject({
name: 'metric-feature',
environments: [
{
name: 'default',
yes: 123,
no: 321,
},
],
});
});

View File

@ -214,6 +214,8 @@ export interface IEnvironmentOverview extends IEnvironmentBase {
variantCount: number;
hasStrategies?: boolean;
hasEnabledStrategies?: boolean;
yes?: number;
no?: number;
}
export interface IFeatureOverview {