mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-24 01:18:01 +02:00
feat: send traffic info to prometheus (#8541)
This commit is contained in:
parent
7c37de373f
commit
677ec9cee8
@ -42,6 +42,8 @@ import FakeStrategiesStore from '../../../test/fixtures/fake-strategies-store';
|
|||||||
import FakeFeatureStrategiesStore from '../feature-toggle/fakes/fake-feature-strategies-store';
|
import FakeFeatureStrategiesStore from '../feature-toggle/fakes/fake-feature-strategies-store';
|
||||||
import { FeatureStrategiesReadModel } from '../feature-toggle/feature-strategies-read-model';
|
import { FeatureStrategiesReadModel } from '../feature-toggle/feature-strategies-read-model';
|
||||||
import { FakeFeatureStrategiesReadModel } from '../feature-toggle/fake-feature-strategies-read-model';
|
import { FakeFeatureStrategiesReadModel } from '../feature-toggle/fake-feature-strategies-read-model';
|
||||||
|
import { TrafficDataUsageStore } from '../traffic-data-usage/traffic-data-usage-store';
|
||||||
|
import { FakeTrafficDataUsageStore } from '../traffic-data-usage/fake-traffic-data-usage-store';
|
||||||
|
|
||||||
export const createInstanceStatsService = (db: Db, config: IUnleashConfig) => {
|
export const createInstanceStatsService = (db: Db, config: IUnleashConfig) => {
|
||||||
const { eventBus, getLogger, flagResolver } = config;
|
const { eventBus, getLogger, flagResolver } = config;
|
||||||
@ -93,6 +95,9 @@ export const createInstanceStatsService = (db: Db, config: IUnleashConfig) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const featureStrategiesReadModel = new FeatureStrategiesReadModel(db);
|
const featureStrategiesReadModel = new FeatureStrategiesReadModel(db);
|
||||||
|
|
||||||
|
const trafficDataUsageStore = new TrafficDataUsageStore(db, getLogger);
|
||||||
|
|
||||||
const instanceStatsServiceStores = {
|
const instanceStatsServiceStores = {
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
userStore,
|
userStore,
|
||||||
@ -109,6 +114,7 @@ export const createInstanceStatsService = (db: Db, config: IUnleashConfig) => {
|
|||||||
apiTokenStore,
|
apiTokenStore,
|
||||||
clientMetricsStoreV2,
|
clientMetricsStoreV2,
|
||||||
featureStrategiesReadModel,
|
featureStrategiesReadModel,
|
||||||
|
trafficDataUsageStore,
|
||||||
};
|
};
|
||||||
const featureStrategiesStore = new FeatureStrategyStore(
|
const featureStrategiesStore = new FeatureStrategyStore(
|
||||||
db,
|
db,
|
||||||
@ -157,6 +163,7 @@ export const createFakeInstanceStatsService = (config: IUnleashConfig) => {
|
|||||||
const apiTokenStore = new FakeApiTokenStore();
|
const apiTokenStore = new FakeApiTokenStore();
|
||||||
const clientMetricsStoreV2 = new FakeClientMetricsStoreV2();
|
const clientMetricsStoreV2 = new FakeClientMetricsStoreV2();
|
||||||
const featureStrategiesReadModel = new FakeFeatureStrategiesReadModel();
|
const featureStrategiesReadModel = new FakeFeatureStrategiesReadModel();
|
||||||
|
const trafficDataUsageStore = new FakeTrafficDataUsageStore();
|
||||||
|
|
||||||
const instanceStatsServiceStores = {
|
const instanceStatsServiceStores = {
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
@ -174,6 +181,7 @@ export const createFakeInstanceStatsService = (config: IUnleashConfig) => {
|
|||||||
apiTokenStore,
|
apiTokenStore,
|
||||||
clientMetricsStoreV2,
|
clientMetricsStoreV2,
|
||||||
featureStrategiesReadModel,
|
featureStrategiesReadModel,
|
||||||
|
trafficDataUsageStore,
|
||||||
};
|
};
|
||||||
const featureStrategiesStore = new FakeFeatureStrategiesStore();
|
const featureStrategiesStore = new FakeFeatureStrategiesStore();
|
||||||
const versionServiceStores = {
|
const versionServiceStores = {
|
||||||
|
@ -6,6 +6,7 @@ import type {
|
|||||||
IClientMetricsStoreV2,
|
IClientMetricsStoreV2,
|
||||||
IEventStore,
|
IEventStore,
|
||||||
IFeatureStrategiesReadModel,
|
IFeatureStrategiesReadModel,
|
||||||
|
ITrafficDataUsageStore,
|
||||||
IUnleashStores,
|
IUnleashStores,
|
||||||
} from '../../types/stores';
|
} from '../../types/stores';
|
||||||
import type { IContextFieldStore } from '../../types/stores/context-field-store';
|
import type { IContextFieldStore } from '../../types/stores/context-field-store';
|
||||||
@ -29,6 +30,7 @@ import { CUSTOM_ROOT_ROLE_TYPE } from '../../util';
|
|||||||
import type { GetActiveUsers } from './getActiveUsers';
|
import type { GetActiveUsers } from './getActiveUsers';
|
||||||
import type { ProjectModeCount } from '../project/project-store';
|
import type { ProjectModeCount } from '../project/project-store';
|
||||||
import type { GetProductionChanges } from './getProductionChanges';
|
import type { GetProductionChanges } from './getProductionChanges';
|
||||||
|
import { format } from 'date-fns';
|
||||||
|
|
||||||
export type TimeRange = 'allTime' | '30d' | '7d';
|
export type TimeRange = 'allTime' | '30d' | '7d';
|
||||||
|
|
||||||
@ -115,6 +117,8 @@ export class InstanceStatsService {
|
|||||||
|
|
||||||
private featureStrategiesReadModel: IFeatureStrategiesReadModel;
|
private featureStrategiesReadModel: IFeatureStrategiesReadModel;
|
||||||
|
|
||||||
|
private trafficDataUsageStore: ITrafficDataUsageStore;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{
|
{
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
@ -132,6 +136,7 @@ export class InstanceStatsService {
|
|||||||
apiTokenStore,
|
apiTokenStore,
|
||||||
clientMetricsStoreV2,
|
clientMetricsStoreV2,
|
||||||
featureStrategiesReadModel,
|
featureStrategiesReadModel,
|
||||||
|
trafficDataUsageStore,
|
||||||
}: Pick<
|
}: Pick<
|
||||||
IUnleashStores,
|
IUnleashStores,
|
||||||
| 'featureToggleStore'
|
| 'featureToggleStore'
|
||||||
@ -149,6 +154,7 @@ export class InstanceStatsService {
|
|||||||
| 'apiTokenStore'
|
| 'apiTokenStore'
|
||||||
| 'clientMetricsStoreV2'
|
| 'clientMetricsStoreV2'
|
||||||
| 'featureStrategiesReadModel'
|
| 'featureStrategiesReadModel'
|
||||||
|
| 'trafficDataUsageStore'
|
||||||
>,
|
>,
|
||||||
{
|
{
|
||||||
getLogger,
|
getLogger,
|
||||||
@ -178,6 +184,7 @@ export class InstanceStatsService {
|
|||||||
this.clientMetricsStore = clientMetricsStoreV2;
|
this.clientMetricsStore = clientMetricsStoreV2;
|
||||||
this.flagResolver = flagResolver;
|
this.flagResolver = flagResolver;
|
||||||
this.featureStrategiesReadModel = featureStrategiesReadModel;
|
this.featureStrategiesReadModel = featureStrategiesReadModel;
|
||||||
|
this.trafficDataUsageStore = trafficDataUsageStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
getProjectModeCount(): Promise<ProjectModeCount[]> {
|
getProjectModeCount(): Promise<ProjectModeCount[]> {
|
||||||
@ -361,6 +368,16 @@ export class InstanceStatsService {
|
|||||||
return this.userStore.countServiceAccounts();
|
return this.userStore.countServiceAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getCurrentTrafficData(): Promise<number> {
|
||||||
|
const traffic =
|
||||||
|
await this.trafficDataUsageStore.getTrafficDataUsageForPeriod(
|
||||||
|
format(new Date(), 'yyyy-MM'),
|
||||||
|
);
|
||||||
|
|
||||||
|
const counts = traffic.map((item) => item.count);
|
||||||
|
return counts.reduce((total, current) => total + current, 0);
|
||||||
|
}
|
||||||
|
|
||||||
async getLabeledAppCounts(): Promise<
|
async getLabeledAppCounts(): Promise<
|
||||||
Partial<{ [key in TimeRange]: number }>
|
Partial<{ [key in TimeRange]: number }>
|
||||||
> {
|
> {
|
||||||
|
@ -3,8 +3,11 @@ import type {
|
|||||||
IStatTrafficUsage,
|
IStatTrafficUsage,
|
||||||
} from './traffic-data-usage-store-type';
|
} from './traffic-data-usage-store-type';
|
||||||
import type { ITrafficDataUsageStore } from '../../types';
|
import type { ITrafficDataUsageStore } from '../../types';
|
||||||
|
import { isSameMonth, parse } from 'date-fns';
|
||||||
|
|
||||||
export class FakeTrafficDataUsageStore implements ITrafficDataUsageStore {
|
export class FakeTrafficDataUsageStore implements ITrafficDataUsageStore {
|
||||||
|
private trafficData: IStatTrafficUsage[] = [];
|
||||||
|
|
||||||
get(key: IStatTrafficUsageKey): Promise<IStatTrafficUsage> {
|
get(key: IStatTrafficUsageKey): Promise<IStatTrafficUsage> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
@ -23,10 +26,28 @@ export class FakeTrafficDataUsageStore implements ITrafficDataUsageStore {
|
|||||||
destroy(): void {
|
destroy(): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
upsert(trafficDataUsage: IStatTrafficUsage): Promise<void> {
|
async upsert(trafficDataUsage: IStatTrafficUsage): Promise<void> {
|
||||||
throw new Error('Method not implemented.');
|
const index = this.trafficData.findIndex(
|
||||||
|
(data) =>
|
||||||
|
data.day.getTime() === trafficDataUsage.day.getTime() &&
|
||||||
|
data.trafficGroup === trafficDataUsage.trafficGroup &&
|
||||||
|
data.statusCodeSeries === trafficDataUsage.statusCodeSeries,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
this.trafficData[index].count += trafficDataUsage.count;
|
||||||
|
} else {
|
||||||
|
this.trafficData.push(trafficDataUsage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
getTrafficDataUsageForPeriod(period: string): Promise<IStatTrafficUsage[]> {
|
|
||||||
throw new Error('Method not implemented.');
|
async getTrafficDataUsageForPeriod(
|
||||||
|
period: string,
|
||||||
|
): Promise<IStatTrafficUsage[]> {
|
||||||
|
const periodDate = parse(period, 'yyyy-MM', new Date());
|
||||||
|
|
||||||
|
return this.trafficData.filter((data) =>
|
||||||
|
isSameMonth(data.day, periodDate),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,3 +351,9 @@ test('should collect limit exceeded metrics', async () => {
|
|||||||
/exceeds_limit_error{resource=\"feature flags\",limit=\"5000\"} 1/,
|
/exceeds_limit_error{resource=\"feature flags\",limit=\"5000\"} 1/,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should collect traffic_total metrics', async () => {
|
||||||
|
const recordedMetric =
|
||||||
|
await prometheusRegister.getSingleMetricAsString('traffic_total');
|
||||||
|
expect(recordedMetric).toMatch(/traffic_total 0/);
|
||||||
|
});
|
||||||
|
@ -277,6 +277,10 @@ export function registerPrometheusMetrics(
|
|||||||
name: 'users_total',
|
name: 'users_total',
|
||||||
help: 'Number of users',
|
help: 'Number of users',
|
||||||
});
|
});
|
||||||
|
const trafficTotal = createGauge({
|
||||||
|
name: 'traffic_total',
|
||||||
|
help: 'Traffic used current month',
|
||||||
|
});
|
||||||
const serviceAccounts = createGauge({
|
const serviceAccounts = createGauge({
|
||||||
name: 'service_accounts_total',
|
name: 'service_accounts_total',
|
||||||
help: 'Number of service accounts',
|
help: 'Number of service accounts',
|
||||||
@ -957,6 +961,11 @@ export function registerPrometheusMetrics(
|
|||||||
await instanceStatsService.countServiceAccounts(),
|
await instanceStatsService.countServiceAccounts(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
trafficTotal.reset();
|
||||||
|
trafficTotal.set(
|
||||||
|
await instanceStatsService.getCurrentTrafficData(),
|
||||||
|
);
|
||||||
|
|
||||||
apiTokens.reset();
|
apiTokens.reset();
|
||||||
|
|
||||||
for (const [
|
for (const [
|
||||||
|
Loading…
Reference in New Issue
Block a user