1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

feat: count created feature links with impact metrics

This commit is contained in:
kwasniew 2025-06-24 10:57:51 +02:00
parent 4289a1c105
commit 783270599b
No known key found for this signature in database
GPG Key ID: 43A7CBC24C119560
6 changed files with 75 additions and 12 deletions

View File

@ -6,13 +6,21 @@ import {
NotFoundError,
OperationDeniedError,
} from '../../error/index.js';
import { fakeImpactMetricsResolver } from '../../../test/fixtures/fake-impact-metrics.js';
test('create, update and delete feature link', async () => {
const flagResolver = { impactMetrics: fakeImpactMetricsResolver() };
const { featureLinkStore, featureLinkService } =
createFakeFeatureLinkService({
getLogger,
flagResolver,
} as unknown as IUnleashConfig);
flagResolver.impactMetrics.defineCounter(
'feature_link_count',
'Count of feature links',
);
const link = await featureLinkService.createLink(
'default',
{
@ -29,6 +37,10 @@ test('create, update and delete feature link', async () => {
domain: 'example',
});
expect(
flagResolver.impactMetrics.counters.get('feature_link_count')!.value,
).toBe(1);
const newLink = await featureLinkService.updateLink(
{ projectId: 'default', linkId: link.id },
{
@ -53,8 +65,10 @@ test('create, update and delete feature link', async () => {
});
test('cannot delete/update non existent link', async () => {
const flagResolver = { impactMetrics: fakeImpactMetricsResolver() };
const { featureLinkService } = createFakeFeatureLinkService({
getLogger,
flagResolver,
} as unknown as IUnleashConfig);
await expect(
@ -77,8 +91,10 @@ test('cannot delete/update non existent link', async () => {
});
test('cannot create/update invalid link', async () => {
const flagResolver = { impactMetrics: fakeImpactMetricsResolver() };
const { featureLinkService } = createFakeFeatureLinkService({
getLogger,
flagResolver,
} as unknown as IUnleashConfig);
await expect(
@ -107,8 +123,10 @@ test('cannot create/update invalid link', async () => {
});
test('cannot exceed allowed link count', async () => {
const flagResolver = { impactMetrics: fakeImpactMetricsResolver() };
const { featureLinkService } = createFakeFeatureLinkService({
getLogger,
flagResolver,
} as unknown as IUnleashConfig);
for (let i = 0; i < 10; i++) {

View File

@ -4,6 +4,7 @@ import {
FeatureLinkRemovedEvent,
FeatureLinkUpdatedEvent,
type IAuditUser,
type IFlagResolver,
type IUnleashConfig,
} from '../../types/index.js';
import type {
@ -18,6 +19,7 @@ import {
} from '../../error/index.js';
import normalizeUrl from 'normalize-url';
import { parse } from 'tldts';
import { FEAUTRE_LINK_COUNT } from '../metrics/impact/define-impact-metrics.js';
interface IFeatureLinkStoreObj {
featureLinkStore: IFeatureLinkStore;
@ -27,15 +29,20 @@ export default class FeatureLinkService {
private logger: Logger;
private featureLinkStore: IFeatureLinkStore;
private eventService: EventService;
private flagResolver: IFlagResolver;
constructor(
stores: IFeatureLinkStoreObj,
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
{
getLogger,
flagResolver,
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>,
eventService: EventService,
) {
this.logger = getLogger('feature-links/feature-link-service.ts');
this.featureLinkStore = stores.featureLinkStore;
this.eventService = eventService;
this.flagResolver = flagResolver;
}
async getAll(): Promise<IFeatureLink[]> {
@ -72,6 +79,8 @@ export default class FeatureLinkService {
domain: domainWithoutSuffix,
});
this.flagResolver.impactMetrics?.incrementCounter(FEAUTRE_LINK_COUNT);
await this.eventService.storeEvent(
new FeatureLinkAddedEvent({
featureName: newLink.featureName,

View File

@ -19,17 +19,7 @@ let featureLinkReadModel: IFeatureLinksReadModel;
beforeAll(async () => {
db = await dbInit('feature_link', getLogger);
app = await setupAppWithAuth(
db.stores,
{
experimental: {
flags: {
featureLinks: true,
},
},
},
db.rawDatabase,
);
app = await setupAppWithAuth(db.stores, {}, db.rawDatabase);
eventStore = db.stores.eventStore;
featureLinkStore = db.stores.featureLinkStore;
featureLinkReadModel = new FeatureLinksReadModel(

View File

@ -0,0 +1,10 @@
import type { IFlagResolver } from '../../../types/index.js';
export const FEAUTRE_LINK_COUNT = 'feature_link_count';
export const defineImpactMetrics = (flagResolver: IFlagResolver) => {
flagResolver.impactMetrics?.defineCounter(
FEAUTRE_LINK_COUNT,
'Count of feature links',
);
};

View File

@ -183,6 +183,7 @@ import { testDbPrefix } from '../test/e2e/helpers/database-init.js';
import type { RequestHandler } from 'express';
import { UPDATE_REVISION } from './features/feature-toggle/configuration-revision-service.js';
import type { IFeatureUsageInfo } from './services/version-service.js';
import { defineImpactMetrics } from './features/metrics/impact/define-impact-metrics.js';
export async function initialServiceSetup(
{ authentication }: Pick<IUnleashConfig, 'authentication'>,
@ -232,6 +233,7 @@ export async function createApp(
scheduleServices(services, config);
}
defineImpactMetrics(config.flagResolver);
const metricsMonitor = fm.createMetricsMonitor();
const unleashSession = fm.createSessionDb(config, db);

View File

@ -0,0 +1,34 @@
export const fakeImpactMetricsResolver = () => ({
counters: new Map<string, { value: number; help: string }>(),
gauges: new Map<string, { value: number; help: string }>(),
defineCounter(name: string, help: string) {
this.counters.set(name, { value: 0, help });
},
defineGauge(name: string, help: string) {
this.gauges.set(name, { value: 0, help });
},
incrementCounter(name: string, value: number = 1) {
const counter = this.counters.get(name);
if (!counter) {
return;
}
counter.value += value;
this.counters.set(name, counter);
},
updateGauge(name: string, value: number) {
const gauge = this.gauges.get(name);
if (!gauge) {
return;
}
gauge.value = value;
this.gauges.set(name, gauge);
},
});