mirror of
https://github.com/Unleash/unleash.git
synced 2025-11-10 01:19:53 +01:00
Migrate more metrics
This commit is contained in:
parent
9015cce47b
commit
d6577d4b80
@ -37,17 +37,39 @@ export class DbMetricsMonitor {
|
|||||||
return Array.isArray(value) ? value : [value];
|
return Array.isArray(value) ? value : [value];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async fetch<T, L extends string>(
|
||||||
|
definition: GaugeDefinition<T, L>,
|
||||||
|
) {
|
||||||
|
const result = await definition.query();
|
||||||
|
if (
|
||||||
|
result !== undefined &&
|
||||||
|
result !== null &&
|
||||||
|
(!Array.isArray(result) || result.length > 0)
|
||||||
|
) {
|
||||||
|
const resultArray = this.asArray(definition.map(result));
|
||||||
|
resultArray
|
||||||
|
.filter((r) => !Number.isInteger(r.value))
|
||||||
|
.forEach((r) => {
|
||||||
|
this.log.warn(
|
||||||
|
`Invalid value for ${definition.name}: ${r.value}. Value must be an integer.`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return resultArray.filter((r) => Number.isInteger(r.value));
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
registerGaugeDbMetric<T, L extends string>(
|
registerGaugeDbMetric<T, L extends string>(
|
||||||
definition: GaugeDefinition<T, L>,
|
definition: GaugeDefinition<T, L>,
|
||||||
): Task {
|
): Task {
|
||||||
const gauge = createGauge(definition);
|
const gauge = createGauge(definition);
|
||||||
const task = async () => {
|
const task = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await definition.query();
|
const results = await this.fetch(definition);
|
||||||
if (result !== null && result !== undefined) {
|
if (results.length > 0) {
|
||||||
const results = this.asArray(definition.map(result));
|
|
||||||
gauge.reset();
|
gauge.reset();
|
||||||
for (const r of results) {
|
for (const r of results) {
|
||||||
|
// when r.value is zero, we are writing a zero value to the gauge which might not be what we want in some cases
|
||||||
if (r.labels) {
|
if (r.labels) {
|
||||||
gauge.labels(r.labels).set(r.value);
|
gauge.labels(r.labels).set(r.value);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -219,20 +219,54 @@ export function registerPrometheusMetrics(
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const maxConstraintsPerStrategy = createGauge({
|
dbMetrics.registerGaugeDbMetric({
|
||||||
name: 'max_strategy_constraints',
|
name: 'max_strategy_constraints',
|
||||||
help: 'Maximum number of constraints used on a single strategy',
|
help: 'Maximum number of constraints used on a single strategy',
|
||||||
labelNames: ['feature', 'environment'],
|
labelNames: ['feature', 'environment'],
|
||||||
|
query: () =>
|
||||||
|
stores.featureStrategiesReadModel.getMaxConstraintsPerStrategy(),
|
||||||
|
map: (result) => ({
|
||||||
|
value: result.count,
|
||||||
|
labels: {
|
||||||
|
environment: result.environment,
|
||||||
|
feature: result.feature,
|
||||||
|
},
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
const largestProjectEnvironment = createGauge({
|
|
||||||
|
dbMetrics.registerGaugeDbMetric({
|
||||||
name: 'largest_project_environment_size',
|
name: 'largest_project_environment_size',
|
||||||
help: 'The largest project environment size (bytes) based on strategies, constraints, variants and parameters',
|
help: 'The largest project environment size (bytes) based on strategies, constraints, variants and parameters',
|
||||||
labelNames: ['project', 'environment'],
|
labelNames: ['project', 'environment'],
|
||||||
|
query: () =>
|
||||||
|
stores.largestResourcesReadModel.getLargestProjectEnvironments(1),
|
||||||
|
map: (results) => {
|
||||||
|
const result = results[0];
|
||||||
|
return {
|
||||||
|
value: result.size,
|
||||||
|
labels: {
|
||||||
|
project: result.project,
|
||||||
|
environment: result.environment,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const largestFeatureEnvironment = createGauge({
|
dbMetrics.registerGaugeDbMetric({
|
||||||
name: 'largest_feature_environment_size',
|
name: 'largest_feature_environment_size',
|
||||||
help: 'The largest feature environment size (bytes) base on strategies, constraints, variants and parameters',
|
help: 'The largest feature environment size (bytes) base on strategies, constraints, variants and parameters',
|
||||||
labelNames: ['feature', 'environment'],
|
labelNames: ['feature', 'environment'],
|
||||||
|
query: () =>
|
||||||
|
stores.largestResourcesReadModel.getLargestFeatureEnvironments(1),
|
||||||
|
map: (results) => {
|
||||||
|
const result = results[0];
|
||||||
|
return {
|
||||||
|
value: result.size,
|
||||||
|
labels: {
|
||||||
|
feature: result.feature,
|
||||||
|
environment: result.environment,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const featureTogglesArchivedTotal = createGauge({
|
const featureTogglesArchivedTotal = createGauge({
|
||||||
@ -473,27 +507,76 @@ export function registerPrometheusMetrics(
|
|||||||
help: 'Duration of mapFeaturesForClient function',
|
help: 'Duration of mapFeaturesForClient function',
|
||||||
});
|
});
|
||||||
|
|
||||||
const featureLifecycleStageDuration = createGauge({
|
dbMetrics.registerGaugeDbMetric({
|
||||||
name: 'feature_lifecycle_stage_duration',
|
name: 'feature_lifecycle_stage_duration',
|
||||||
labelNames: ['stage', 'project_id'],
|
labelNames: ['stage', 'project_id'],
|
||||||
help: 'Duration of feature lifecycle stages',
|
help: 'Duration of feature lifecycle stages',
|
||||||
|
query: () => stores.featureLifecycleReadModel.getAllWithStageDuration(),
|
||||||
|
map: (result) =>
|
||||||
|
result.map((stageResult) => ({
|
||||||
|
value: stageResult.duration,
|
||||||
|
labels: {
|
||||||
|
project_id: stageResult.project,
|
||||||
|
stage: stageResult.stage,
|
||||||
|
},
|
||||||
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
const onboardingDuration = createGauge({
|
dbMetrics.registerGaugeDbMetric({
|
||||||
name: 'onboarding_duration',
|
name: 'onboarding_duration',
|
||||||
labelNames: ['event'],
|
labelNames: ['event'],
|
||||||
help: 'firstLogin, secondLogin, firstFeatureFlag, firstPreLive, firstLive from first user creation',
|
help: 'firstLogin, secondLogin, firstFeatureFlag, firstPreLive, firstLive from first user creation',
|
||||||
|
query: () =>
|
||||||
|
flagResolver.isEnabled('onboardingMetrics')
|
||||||
|
? stores.onboardingReadModel.getInstanceOnboardingMetrics()
|
||||||
|
: Promise.resolve({}),
|
||||||
|
map: (result) =>
|
||||||
|
Object.keys(result)
|
||||||
|
.filter((key) => Number.isInteger(result[key]))
|
||||||
|
.map((key) => ({
|
||||||
|
value: result[key],
|
||||||
|
labels: {
|
||||||
|
event: key,
|
||||||
|
},
|
||||||
|
})),
|
||||||
});
|
});
|
||||||
const projectOnboardingDuration = createGauge({
|
|
||||||
|
dbMetrics.registerGaugeDbMetric({
|
||||||
name: 'project_onboarding_duration',
|
name: 'project_onboarding_duration',
|
||||||
labelNames: ['event', 'project'],
|
labelNames: ['event', 'project'],
|
||||||
help: 'firstFeatureFlag, firstPreLive, firstLive from project creation',
|
help: 'firstFeatureFlag, firstPreLive, firstLive from project creation',
|
||||||
|
query: () =>
|
||||||
|
flagResolver.isEnabled('onboardingMetrics')
|
||||||
|
? stores.onboardingReadModel.getProjectsOnboardingMetrics()
|
||||||
|
: Promise.resolve([]),
|
||||||
|
map: (projectsOnboardingMetrics) =>
|
||||||
|
projectsOnboardingMetrics.flatMap(
|
||||||
|
({ project, ...projectMetrics }) =>
|
||||||
|
Object.keys(projectMetrics)
|
||||||
|
.filter((key) => Number.isInteger(projectMetrics[key]))
|
||||||
|
.map((key) => ({
|
||||||
|
value: projectMetrics[key],
|
||||||
|
labels: {
|
||||||
|
event: key,
|
||||||
|
project,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const featureLifecycleStageCountByProject = createGauge({
|
dbMetrics.registerGaugeDbMetric({
|
||||||
name: 'feature_lifecycle_stage_count_by_project',
|
name: 'feature_lifecycle_stage_count_by_project',
|
||||||
help: 'Count features in a given stage by project id',
|
help: 'Count features in a given stage by project id',
|
||||||
labelNames: ['stage', 'project_id'],
|
labelNames: ['stage', 'project_id'],
|
||||||
|
query: () => stores.featureLifecycleReadModel.getStageCountByProject(),
|
||||||
|
map: (result) =>
|
||||||
|
result.map((stageResult) => ({
|
||||||
|
value: stageResult.count,
|
||||||
|
labels: {
|
||||||
|
project_id: stageResult.project,
|
||||||
|
stage: stageResult.stage,
|
||||||
|
},
|
||||||
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
const featureLifecycleStageEnteredCounter = createCounter({
|
const featureLifecycleStageEnteredCounter = createCounter({
|
||||||
@ -858,34 +941,6 @@ export function registerPrometheusMetrics(
|
|||||||
collectDbMetrics: dbMetrics.refreshDbMetrics,
|
collectDbMetrics: dbMetrics.refreshDbMetrics,
|
||||||
collectStaticCounters: async () => {
|
collectStaticCounters: async () => {
|
||||||
try {
|
try {
|
||||||
const [
|
|
||||||
maxConstraintsPerStrategyResult,
|
|
||||||
stageCountByProjectResult,
|
|
||||||
stageDurationByProject,
|
|
||||||
largestProjectEnvironments,
|
|
||||||
largestFeatureEnvironments,
|
|
||||||
deprecatedTokens,
|
|
||||||
instanceOnboardingMetrics,
|
|
||||||
projectsOnboardingMetrics,
|
|
||||||
] = await Promise.all([
|
|
||||||
stores.featureStrategiesReadModel.getMaxConstraintsPerStrategy(),
|
|
||||||
stores.featureLifecycleReadModel.getStageCountByProject(),
|
|
||||||
stores.featureLifecycleReadModel.getAllWithStageDuration(),
|
|
||||||
stores.largestResourcesReadModel.getLargestProjectEnvironments(
|
|
||||||
1,
|
|
||||||
),
|
|
||||||
stores.largestResourcesReadModel.getLargestFeatureEnvironments(
|
|
||||||
1,
|
|
||||||
),
|
|
||||||
stores.apiTokenStore.countDeprecatedTokens(),
|
|
||||||
flagResolver.isEnabled('onboardingMetrics')
|
|
||||||
? stores.onboardingReadModel.getInstanceOnboardingMetrics()
|
|
||||||
: Promise.resolve({}),
|
|
||||||
flagResolver.isEnabled('onboardingMetrics')
|
|
||||||
? stores.onboardingReadModel.getProjectsOnboardingMetrics()
|
|
||||||
: Promise.resolve([]),
|
|
||||||
]);
|
|
||||||
|
|
||||||
featureTogglesArchivedTotal.reset();
|
featureTogglesArchivedTotal.reset();
|
||||||
featureTogglesArchivedTotal.set(
|
featureTogglesArchivedTotal.set(
|
||||||
await instanceStatsService.getArchivedToggleCount(),
|
await instanceStatsService.getArchivedToggleCount(),
|
||||||
@ -899,25 +954,6 @@ export function registerPrometheusMetrics(
|
|||||||
await instanceStatsService.countServiceAccounts(),
|
await instanceStatsService.countServiceAccounts(),
|
||||||
);
|
);
|
||||||
|
|
||||||
stageDurationByProject.forEach((stage) => {
|
|
||||||
featureLifecycleStageDuration
|
|
||||||
.labels({
|
|
||||||
stage: stage.stage,
|
|
||||||
project_id: stage.project,
|
|
||||||
})
|
|
||||||
.set(stage.duration);
|
|
||||||
});
|
|
||||||
|
|
||||||
featureLifecycleStageCountByProject.reset();
|
|
||||||
stageCountByProjectResult.forEach((stageResult) =>
|
|
||||||
featureLifecycleStageCountByProject
|
|
||||||
.labels({
|
|
||||||
project_id: stageResult.project,
|
|
||||||
stage: stageResult.stage,
|
|
||||||
})
|
|
||||||
.set(stageResult.count),
|
|
||||||
);
|
|
||||||
|
|
||||||
apiTokens.reset();
|
apiTokens.reset();
|
||||||
|
|
||||||
for (const [
|
for (const [
|
||||||
@ -927,6 +963,8 @@ export function registerPrometheusMetrics(
|
|||||||
apiTokens.labels({ type }).set(value);
|
apiTokens.labels({ type }).set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deprecatedTokens =
|
||||||
|
await stores.apiTokenStore.countDeprecatedTokens();
|
||||||
orphanedTokensTotal.reset();
|
orphanedTokensTotal.reset();
|
||||||
orphanedTokensTotal.set(deprecatedTokens.orphanedTokens);
|
orphanedTokensTotal.set(deprecatedTokens.orphanedTokens);
|
||||||
|
|
||||||
@ -939,60 +977,6 @@ export function registerPrometheusMetrics(
|
|||||||
legacyTokensActive.reset();
|
legacyTokensActive.reset();
|
||||||
legacyTokensActive.set(deprecatedTokens.activeLegacyTokens);
|
legacyTokensActive.set(deprecatedTokens.activeLegacyTokens);
|
||||||
|
|
||||||
if (maxConstraintsPerStrategyResult) {
|
|
||||||
maxConstraintsPerStrategy.reset();
|
|
||||||
maxConstraintsPerStrategy
|
|
||||||
.labels({
|
|
||||||
environment:
|
|
||||||
maxConstraintsPerStrategyResult.environment,
|
|
||||||
feature: maxConstraintsPerStrategyResult.feature,
|
|
||||||
})
|
|
||||||
.set(maxConstraintsPerStrategyResult.count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (largestProjectEnvironments.length > 0) {
|
|
||||||
const projectEnvironment = largestProjectEnvironments[0];
|
|
||||||
largestProjectEnvironment.reset();
|
|
||||||
largestProjectEnvironment
|
|
||||||
.labels({
|
|
||||||
project: projectEnvironment.project,
|
|
||||||
environment: projectEnvironment.environment,
|
|
||||||
})
|
|
||||||
.set(projectEnvironment.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (largestFeatureEnvironments.length > 0) {
|
|
||||||
const featureEnvironment = largestFeatureEnvironments[0];
|
|
||||||
largestFeatureEnvironment.reset();
|
|
||||||
largestFeatureEnvironment
|
|
||||||
.labels({
|
|
||||||
feature: featureEnvironment.feature,
|
|
||||||
environment: featureEnvironment.environment,
|
|
||||||
})
|
|
||||||
.set(featureEnvironment.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(instanceOnboardingMetrics).forEach((key) => {
|
|
||||||
if (Number.isInteger(instanceOnboardingMetrics[key])) {
|
|
||||||
onboardingDuration
|
|
||||||
.labels({
|
|
||||||
event: key,
|
|
||||||
})
|
|
||||||
.set(instanceOnboardingMetrics[key]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
projectsOnboardingMetrics.forEach(
|
|
||||||
({ project, ...projectMetrics }) => {
|
|
||||||
Object.keys(projectMetrics).forEach((key) => {
|
|
||||||
if (Number.isInteger(projectMetrics[key])) {
|
|
||||||
projectOnboardingDuration
|
|
||||||
.labels({ event: key, project })
|
|
||||||
.set(projectMetrics[key]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const [resource, limit] of Object.entries(
|
for (const [resource, limit] of Object.entries(
|
||||||
config.resourceLimits,
|
config.resourceLimits,
|
||||||
)) {
|
)) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user