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:
parent
07871e73e5
commit
77d5156eba
@ -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) {
|
||||
|
@ -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,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
@ -214,6 +214,8 @@ export interface IEnvironmentOverview extends IEnvironmentBase {
|
||||
variantCount: number;
|
||||
hasStrategies?: boolean;
|
||||
hasEnabledStrategies?: boolean;
|
||||
yes?: number;
|
||||
no?: number;
|
||||
}
|
||||
|
||||
export interface IFeatureOverview {
|
||||
|
Loading…
Reference in New Issue
Block a user