mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-17 01:17:29 +02:00
fix: add metrics for service account and api tokens (#5478)
This commit is contained in:
parent
961655d5dd
commit
07fcdbb053
@ -96,12 +96,26 @@ export class ApiTokenStore implements IApiTokenStore {
|
||||
});
|
||||
}
|
||||
|
||||
count(): Promise<number> {
|
||||
async count(): Promise<number> {
|
||||
return this.db(TABLE)
|
||||
.count('*')
|
||||
.then((res) => Number(res[0].count));
|
||||
}
|
||||
|
||||
async countByType(): Promise<Map<string, number>> {
|
||||
return this.db(TABLE)
|
||||
.select('type')
|
||||
.count('*')
|
||||
.groupBy('type')
|
||||
.then((res) => {
|
||||
const map = new Map<string, number>();
|
||||
res.forEach((row) => {
|
||||
map.set(row.type.toString(), Number(row.count));
|
||||
});
|
||||
return map;
|
||||
});
|
||||
}
|
||||
|
||||
async getAll(): Promise<IApiToken[]> {
|
||||
const stopTimer = this.timer('getAll');
|
||||
const rows = await this.makeTokenProjectQuery();
|
||||
|
@ -201,6 +201,16 @@ class UserStore implements IUserStore {
|
||||
.then((res) => Number(res[0].count));
|
||||
}
|
||||
|
||||
async countServiceAccounts(): Promise<number> {
|
||||
return this.db(TABLE)
|
||||
.where({
|
||||
deleted_at: null,
|
||||
is_service: true,
|
||||
})
|
||||
.count('*')
|
||||
.then((res) => Number(res[0].count));
|
||||
}
|
||||
|
||||
destroy(): void {}
|
||||
|
||||
async exists(id: number): Promise<boolean> {
|
||||
|
@ -17,7 +17,11 @@ import { ISegmentStore } from '../../types/stores/segment-store';
|
||||
import { IRoleStore } from '../../types/stores/role-store';
|
||||
import VersionService from '../../services/version-service';
|
||||
import { ISettingStore } from '../../types/stores/settings-store';
|
||||
import { FEATURES_EXPORTED, FEATURES_IMPORTED } from '../../types';
|
||||
import {
|
||||
FEATURES_EXPORTED,
|
||||
FEATURES_IMPORTED,
|
||||
IApiTokenStore,
|
||||
} from '../../types';
|
||||
import { CUSTOM_ROOT_ROLE_TYPE } from '../../util';
|
||||
import { type GetActiveUsers } from './getActiveUsers';
|
||||
import { ProjectModeCount } from '../../db/project-store';
|
||||
@ -31,6 +35,8 @@ export interface InstanceStats {
|
||||
versionOSS: string;
|
||||
versionEnterprise?: string;
|
||||
users: number;
|
||||
serviceAccounts: number;
|
||||
apiTokens: Map<string, number>;
|
||||
featureToggles: number;
|
||||
projects: ProjectModeCount[];
|
||||
contextFields: number;
|
||||
@ -78,6 +84,8 @@ export class InstanceStatsService {
|
||||
|
||||
private eventStore: IEventStore;
|
||||
|
||||
private apiTokenStore: IApiTokenStore;
|
||||
|
||||
private versionService: VersionService;
|
||||
|
||||
private settingStore: ISettingStore;
|
||||
@ -106,6 +114,7 @@ export class InstanceStatsService {
|
||||
settingStore,
|
||||
clientInstanceStore,
|
||||
eventStore,
|
||||
apiTokenStore,
|
||||
}: Pick<
|
||||
IUnleashStores,
|
||||
| 'featureToggleStore'
|
||||
@ -120,6 +129,7 @@ export class InstanceStatsService {
|
||||
| 'settingStore'
|
||||
| 'clientInstanceStore'
|
||||
| 'eventStore'
|
||||
| 'apiTokenStore'
|
||||
>,
|
||||
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>,
|
||||
versionService: VersionService,
|
||||
@ -142,6 +152,7 @@ export class InstanceStatsService {
|
||||
this.logger = getLogger('services/stats-service.js');
|
||||
this.getActiveUsers = getActiveUsers;
|
||||
this.getProductionChanges = getProductionChanges;
|
||||
this.apiTokenStore = apiTokenStore;
|
||||
}
|
||||
|
||||
async refreshStatsSnapshot(): Promise<void> {
|
||||
@ -194,6 +205,8 @@ export class InstanceStatsService {
|
||||
const [
|
||||
featureToggles,
|
||||
users,
|
||||
serviceAccounts,
|
||||
apiTokens,
|
||||
activeUsers,
|
||||
projects,
|
||||
contextFields,
|
||||
@ -213,6 +226,8 @@ export class InstanceStatsService {
|
||||
] = await Promise.all([
|
||||
this.getToggleCount(),
|
||||
this.userStore.count(),
|
||||
this.userStore.countServiceAccounts(),
|
||||
this.apiTokenStore.countByType(),
|
||||
this.getActiveUsers(),
|
||||
this.getProjectModeCount(),
|
||||
this.contextFieldStore.count(),
|
||||
@ -237,6 +252,8 @@ export class InstanceStatsService {
|
||||
versionOSS: versionInfo.current.oss,
|
||||
versionEnterprise: versionInfo.current.enterprise,
|
||||
users,
|
||||
serviceAccounts,
|
||||
apiTokens,
|
||||
activeUsers,
|
||||
featureToggles,
|
||||
projects,
|
||||
|
@ -31,8 +31,8 @@ export default class MetricsMonitor {
|
||||
poolMetricsTimer?: Timer;
|
||||
|
||||
constructor() {
|
||||
this.timer = null;
|
||||
this.poolMetricsTimer = null;
|
||||
this.timer = undefined;
|
||||
this.poolMetricsTimer = undefined;
|
||||
}
|
||||
|
||||
startMonitoring(
|
||||
@ -44,7 +44,7 @@ export default class MetricsMonitor {
|
||||
db: Knex,
|
||||
): Promise<void> {
|
||||
if (!config.server.serverMetrics) {
|
||||
return;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const { eventStore } = stores;
|
||||
@ -94,6 +94,15 @@ export default class MetricsMonitor {
|
||||
name: 'users_total',
|
||||
help: 'Number of users',
|
||||
});
|
||||
const serviceAccounts = new client.Gauge({
|
||||
name: 'service_accounts_total',
|
||||
help: 'Number of service accounts',
|
||||
});
|
||||
const apiTokens = new client.Gauge({
|
||||
name: 'api_tokens_total',
|
||||
help: 'Number of API tokens',
|
||||
labelNames: ['type'],
|
||||
});
|
||||
const usersActive7days = new client.Gauge({
|
||||
name: 'users_active_7',
|
||||
help: 'Number of users active in the last 7 days',
|
||||
@ -214,6 +223,15 @@ export default class MetricsMonitor {
|
||||
usersTotal.reset();
|
||||
usersTotal.set(stats.users);
|
||||
|
||||
serviceAccounts.reset();
|
||||
serviceAccounts.set(stats.serviceAccounts);
|
||||
|
||||
apiTokens.reset();
|
||||
|
||||
for (const [type, value] of stats.apiTokens) {
|
||||
apiTokens.labels(type).set(value);
|
||||
}
|
||||
|
||||
usersActive7days.reset();
|
||||
usersActive7days.set(stats.activeUsers.last7);
|
||||
usersActive30days.reset();
|
||||
@ -420,6 +438,8 @@ export default class MetricsMonitor {
|
||||
});
|
||||
|
||||
this.configureDbMetrics(db, eventBus);
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
stopMonitoring(): void {
|
||||
|
@ -105,6 +105,8 @@ class InstanceAdminController extends Controller {
|
||||
sum: 'some-sha256-hash',
|
||||
timestamp: new Date(2023, 6, 12, 10, 0, 0, 0),
|
||||
users: 10,
|
||||
serviceAccounts: 2,
|
||||
apiTokens: new Map([]),
|
||||
versionEnterprise: '5.1.7',
|
||||
versionOSS: '5.1.7',
|
||||
activeUsers: {
|
||||
|
@ -7,4 +7,5 @@ export interface IApiTokenStore extends Store<IApiToken, string> {
|
||||
setExpiry(secret: string, expiresAt: Date): Promise<IApiToken>;
|
||||
markSeenAt(secrets: string[]): Promise<void>;
|
||||
count(): Promise<number>;
|
||||
countByType(): Promise<Map<string, number>>;
|
||||
}
|
||||
|
@ -32,4 +32,5 @@ export interface IUserStore extends Store<IUser, number> {
|
||||
incLoginAttempts(user: IUser): Promise<void>;
|
||||
successfullyLogin(user: IUser): Promise<void>;
|
||||
count(): Promise<number>;
|
||||
countServiceAccounts(): Promise<number>;
|
||||
}
|
||||
|
9
src/test/fixtures/fake-api-token-store.ts
vendored
9
src/test/fixtures/fake-api-token-store.ts
vendored
@ -1,5 +1,9 @@
|
||||
import { IApiTokenStore } from '../../lib/types/stores/api-token-store';
|
||||
import { IApiToken, IApiTokenCreate } from '../../lib/types/models/api-token';
|
||||
import {
|
||||
ApiTokenType,
|
||||
IApiToken,
|
||||
IApiTokenCreate,
|
||||
} from '../../lib/types/models/api-token';
|
||||
|
||||
import NotFoundError from '../../lib/error/notfound-error';
|
||||
import EventEmitter from 'events';
|
||||
@ -8,6 +12,9 @@ export default class FakeApiTokenStore
|
||||
extends EventEmitter
|
||||
implements IApiTokenStore
|
||||
{
|
||||
countByType(): Promise<Map<ApiTokenType, number>> {
|
||||
return Promise.resolve(new Map());
|
||||
}
|
||||
tokens: IApiToken[] = [];
|
||||
|
||||
async delete(key: string): Promise<void> {
|
||||
|
3
src/test/fixtures/fake-user-store.ts
vendored
3
src/test/fixtures/fake-user-store.ts
vendored
@ -14,6 +14,9 @@ class UserStoreMock implements IUserStore {
|
||||
this.idSeq = 1;
|
||||
this.data = [];
|
||||
}
|
||||
countServiceAccounts(): Promise<number> {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
async hasUser({
|
||||
id,
|
||||
|
Loading…
Reference in New Issue
Block a user