mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-11 00:08:30 +01:00
refactor: add typesafe wrappers for prom client metrics (#5969)
https://linear.app/unleash/issue/2-1856/add-typesafe-wrappers-over-prom-clients-metrics As discussed on the latest knowledge sharing session, this adds typesafe wrappers over prom client's metrics, requiring us to specify all the configured labels for each metric. This uses a functional approach and only exposes the methods that are currently relevant to us, while also exposing the underlying instance of the metric for an easy access if needed. Since we often chain `labels` with `inc` in counters, this adds a convenience `increment` method for counters which does both in a single call.
This commit is contained in:
parent
77fcc9e840
commit
5253482f61
@ -1,4 +1,4 @@
|
||||
import client from 'prom-client';
|
||||
import { collectDefaultMetrics } from 'prom-client';
|
||||
import memoizee from 'memoizee';
|
||||
import EventEmitter from 'events';
|
||||
import { Knex } from 'knex';
|
||||
@ -25,6 +25,7 @@ import { hoursToMilliseconds, minutesToMilliseconds } from 'date-fns';
|
||||
import { InstanceStatsService } from './features/instance-stats/instance-stats-service';
|
||||
import { ValidatedClientMetrics } from './features/metrics/shared/schema';
|
||||
import { IEnvironment } from './types';
|
||||
import { createCounter, createGauge, createSummary } from './util/metrics';
|
||||
|
||||
export default class MetricsMonitor {
|
||||
timer?: NodeJS.Timeout;
|
||||
@ -58,9 +59,9 @@ export default class MetricsMonitor {
|
||||
},
|
||||
);
|
||||
|
||||
client.collectDefaultMetrics();
|
||||
collectDefaultMetrics();
|
||||
|
||||
const requestDuration = new client.Summary({
|
||||
const requestDuration = createSummary({
|
||||
name: 'http_request_duration_milliseconds',
|
||||
help: 'App response time',
|
||||
labelNames: ['path', 'method', 'status', 'appName'],
|
||||
@ -68,7 +69,7 @@ export default class MetricsMonitor {
|
||||
maxAgeSeconds: 600,
|
||||
ageBuckets: 5,
|
||||
});
|
||||
const schedulerDuration = new client.Summary({
|
||||
const schedulerDuration = createSummary({
|
||||
name: 'scheduler_duration_seconds',
|
||||
help: 'Scheduler duration time',
|
||||
labelNames: ['jobId'],
|
||||
@ -76,7 +77,7 @@ export default class MetricsMonitor {
|
||||
maxAgeSeconds: 600,
|
||||
ageBuckets: 5,
|
||||
});
|
||||
const dbDuration = new client.Summary({
|
||||
const dbDuration = createSummary({
|
||||
name: 'db_query_duration_seconds',
|
||||
help: 'DB query duration time',
|
||||
labelNames: ['store', 'action'],
|
||||
@ -84,141 +85,141 @@ export default class MetricsMonitor {
|
||||
maxAgeSeconds: 600,
|
||||
ageBuckets: 5,
|
||||
});
|
||||
const featureToggleUpdateTotal = new client.Counter({
|
||||
const featureToggleUpdateTotal = createCounter({
|
||||
name: 'feature_toggle_update_total',
|
||||
help: 'Number of times a toggle has been updated. Environment label would be "n/a" when it is not available, e.g. when a feature toggle is created.',
|
||||
labelNames: ['toggle', 'project', 'environment', 'environmentType'],
|
||||
});
|
||||
const featureToggleUsageTotal = new client.Counter({
|
||||
const featureToggleUsageTotal = createCounter({
|
||||
name: 'feature_toggle_usage_total',
|
||||
help: 'Number of times a feature toggle has been used',
|
||||
labelNames: ['toggle', 'active', 'appName'],
|
||||
});
|
||||
const featureTogglesTotal = new client.Gauge({
|
||||
const featureTogglesTotal = createGauge({
|
||||
name: 'feature_toggles_total',
|
||||
help: 'Number of feature toggles',
|
||||
labelNames: ['version'],
|
||||
});
|
||||
const usersTotal = new client.Gauge({
|
||||
const usersTotal = createGauge({
|
||||
name: 'users_total',
|
||||
help: 'Number of users',
|
||||
});
|
||||
const serviceAccounts = new client.Gauge({
|
||||
const serviceAccounts = createGauge({
|
||||
name: 'service_accounts_total',
|
||||
help: 'Number of service accounts',
|
||||
});
|
||||
const apiTokens = new client.Gauge({
|
||||
const apiTokens = createGauge({
|
||||
name: 'api_tokens_total',
|
||||
help: 'Number of API tokens',
|
||||
labelNames: ['type'],
|
||||
});
|
||||
const enabledMetricsBucketsPreviousDay = new client.Gauge({
|
||||
const enabledMetricsBucketsPreviousDay = createGauge({
|
||||
name: 'enabled_metrics_buckets_previous_day',
|
||||
help: 'Number of hourly enabled/disabled metric buckets in the previous day',
|
||||
});
|
||||
const variantMetricsBucketsPreviousDay = new client.Gauge({
|
||||
const variantMetricsBucketsPreviousDay = createGauge({
|
||||
name: 'variant_metrics_buckets_previous_day',
|
||||
help: 'Number of hourly variant metric buckets in the previous day',
|
||||
});
|
||||
const usersActive7days = new client.Gauge({
|
||||
const usersActive7days = createGauge({
|
||||
name: 'users_active_7',
|
||||
help: 'Number of users active in the last 7 days',
|
||||
});
|
||||
const usersActive30days = new client.Gauge({
|
||||
const usersActive30days = createGauge({
|
||||
name: 'users_active_30',
|
||||
help: 'Number of users active in the last 30 days',
|
||||
});
|
||||
const usersActive60days = new client.Gauge({
|
||||
const usersActive60days = createGauge({
|
||||
name: 'users_active_60',
|
||||
help: 'Number of users active in the last 60 days',
|
||||
});
|
||||
const usersActive90days = new client.Gauge({
|
||||
const usersActive90days = createGauge({
|
||||
name: 'users_active_90',
|
||||
help: 'Number of users active in the last 90 days',
|
||||
});
|
||||
const projectsTotal = new client.Gauge({
|
||||
const projectsTotal = createGauge({
|
||||
name: 'projects_total',
|
||||
help: 'Number of projects',
|
||||
labelNames: ['mode'],
|
||||
});
|
||||
const environmentsTotal = new client.Gauge({
|
||||
const environmentsTotal = createGauge({
|
||||
name: 'environments_total',
|
||||
help: 'Number of environments',
|
||||
});
|
||||
const groupsTotal = new client.Gauge({
|
||||
const groupsTotal = createGauge({
|
||||
name: 'groups_total',
|
||||
help: 'Number of groups',
|
||||
});
|
||||
|
||||
const rolesTotal = new client.Gauge({
|
||||
const rolesTotal = createGauge({
|
||||
name: 'roles_total',
|
||||
help: 'Number of roles',
|
||||
});
|
||||
|
||||
const customRootRolesTotal = new client.Gauge({
|
||||
const customRootRolesTotal = createGauge({
|
||||
name: 'custom_root_roles_total',
|
||||
help: 'Number of custom root roles',
|
||||
});
|
||||
|
||||
const customRootRolesInUseTotal = new client.Gauge({
|
||||
const customRootRolesInUseTotal = createGauge({
|
||||
name: 'custom_root_roles_in_use_total',
|
||||
help: 'Number of custom root roles in use',
|
||||
});
|
||||
|
||||
const segmentsTotal = new client.Gauge({
|
||||
const segmentsTotal = createGauge({
|
||||
name: 'segments_total',
|
||||
help: 'Number of segments',
|
||||
});
|
||||
|
||||
const contextTotal = new client.Gauge({
|
||||
const contextTotal = createGauge({
|
||||
name: 'context_total',
|
||||
help: 'Number of context',
|
||||
});
|
||||
|
||||
const strategiesTotal = new client.Gauge({
|
||||
const strategiesTotal = createGauge({
|
||||
name: 'strategies_total',
|
||||
help: 'Number of strategies',
|
||||
});
|
||||
|
||||
const clientAppsTotal = new client.Gauge({
|
||||
const clientAppsTotal = createGauge({
|
||||
name: 'client_apps_total',
|
||||
help: 'Number of registered client apps aggregated by range by last seen',
|
||||
labelNames: ['range'],
|
||||
});
|
||||
|
||||
const samlEnabled = new client.Gauge({
|
||||
const samlEnabled = createGauge({
|
||||
name: 'saml_enabled',
|
||||
help: 'Whether SAML is enabled',
|
||||
});
|
||||
|
||||
const oidcEnabled = new client.Gauge({
|
||||
const oidcEnabled = createGauge({
|
||||
name: 'oidc_enabled',
|
||||
help: 'Whether OIDC is enabled',
|
||||
});
|
||||
|
||||
const clientSdkVersionUsage = new client.Counter({
|
||||
const clientSdkVersionUsage = createCounter({
|
||||
name: 'client_sdk_versions',
|
||||
help: 'Which sdk versions are being used',
|
||||
labelNames: ['sdk_name', 'sdk_version'],
|
||||
});
|
||||
|
||||
const productionChanges30 = new client.Gauge({
|
||||
const productionChanges30 = createGauge({
|
||||
name: 'production_changes_30',
|
||||
help: 'Changes made to production environment last 30 days',
|
||||
labelNames: ['environment'],
|
||||
});
|
||||
const productionChanges60 = new client.Gauge({
|
||||
const productionChanges60 = createGauge({
|
||||
name: 'production_changes_60',
|
||||
help: 'Changes made to production environment last 60 days',
|
||||
labelNames: ['environment'],
|
||||
});
|
||||
const productionChanges90 = new client.Gauge({
|
||||
const productionChanges90 = createGauge({
|
||||
name: 'production_changes_90',
|
||||
help: 'Changes made to production environment last 90 days',
|
||||
labelNames: ['environment'],
|
||||
});
|
||||
|
||||
const rateLimits = new client.Gauge({
|
||||
const rateLimits = createGauge({
|
||||
name: 'rate_limits',
|
||||
help: 'Rate limits (per minute) for METHOD/ENDPOINT pairs',
|
||||
labelNames: ['endpoint', 'method'],
|
||||
@ -229,7 +230,9 @@ export default class MetricsMonitor {
|
||||
const stats = await instanceStatsService.getStats();
|
||||
|
||||
featureTogglesTotal.reset();
|
||||
featureTogglesTotal.labels(version).set(stats.featureToggles);
|
||||
featureTogglesTotal
|
||||
.labels({ version })
|
||||
.set(stats.featureToggles);
|
||||
|
||||
usersTotal.reset();
|
||||
usersTotal.set(stats.users);
|
||||
@ -240,7 +243,7 @@ export default class MetricsMonitor {
|
||||
apiTokens.reset();
|
||||
|
||||
for (const [type, value] of stats.apiTokens) {
|
||||
apiTokens.labels(type).set(value);
|
||||
apiTokens.labels({ type }).set(value);
|
||||
}
|
||||
|
||||
enabledMetricsBucketsPreviousDay.reset();
|
||||
@ -362,7 +365,7 @@ export default class MetricsMonitor {
|
||||
events.REQUEST_TIME,
|
||||
({ path, method, time, statusCode, appName }) => {
|
||||
requestDuration
|
||||
.labels(path, method, statusCode, appName)
|
||||
.labels({ path, method, status: statusCode, appName })
|
||||
.observe(time);
|
||||
},
|
||||
);
|
||||
@ -372,28 +375,40 @@ export default class MetricsMonitor {
|
||||
});
|
||||
|
||||
eventBus.on(events.DB_TIME, ({ store, action, time }) => {
|
||||
dbDuration.labels(store, action).observe(time);
|
||||
dbDuration.labels({ store, action }).observe(time);
|
||||
});
|
||||
|
||||
eventStore.on(FEATURE_CREATED, ({ featureName, project }) => {
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, 'n/a', 'n/a')
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment: 'n/a',
|
||||
environmentType: 'n/a',
|
||||
});
|
||||
});
|
||||
eventStore.on(FEATURE_VARIANTS_UPDATED, ({ featureName, project }) => {
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, 'n/a', 'n/a')
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment: 'n/a',
|
||||
environmentType: 'n/a',
|
||||
});
|
||||
});
|
||||
eventStore.on(FEATURE_METADATA_UPDATED, ({ featureName, project }) => {
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, 'n/a', 'n/a')
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment: 'n/a',
|
||||
environmentType: 'n/a',
|
||||
});
|
||||
});
|
||||
eventStore.on(FEATURE_UPDATED, ({ featureName, project }) => {
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, 'default', 'production')
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment: 'default',
|
||||
environmentType: 'production',
|
||||
});
|
||||
});
|
||||
eventStore.on(
|
||||
FEATURE_STRATEGY_ADD,
|
||||
@ -402,9 +417,12 @@ export default class MetricsMonitor {
|
||||
environment,
|
||||
cachedEnvironments,
|
||||
);
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, environment, environmentType)
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment,
|
||||
environmentType,
|
||||
});
|
||||
},
|
||||
);
|
||||
eventStore.on(
|
||||
@ -414,9 +432,12 @@ export default class MetricsMonitor {
|
||||
environment,
|
||||
cachedEnvironments,
|
||||
);
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, environment, environmentType)
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment,
|
||||
environmentType,
|
||||
});
|
||||
},
|
||||
);
|
||||
eventStore.on(
|
||||
@ -426,9 +447,12 @@ export default class MetricsMonitor {
|
||||
environment,
|
||||
cachedEnvironments,
|
||||
);
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, environment, environmentType)
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment,
|
||||
environmentType,
|
||||
});
|
||||
},
|
||||
);
|
||||
eventStore.on(
|
||||
@ -438,9 +462,12 @@ export default class MetricsMonitor {
|
||||
environment,
|
||||
cachedEnvironments,
|
||||
);
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, environment, environmentType)
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment,
|
||||
environmentType,
|
||||
});
|
||||
},
|
||||
);
|
||||
eventStore.on(
|
||||
@ -450,36 +477,58 @@ export default class MetricsMonitor {
|
||||
environment,
|
||||
cachedEnvironments,
|
||||
);
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, environment, environmentType)
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment,
|
||||
environmentType,
|
||||
});
|
||||
},
|
||||
);
|
||||
eventStore.on(FEATURE_ARCHIVED, ({ featureName, project }) => {
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, 'n/a', 'n/a')
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment: 'n/a',
|
||||
environmentType: 'n/a',
|
||||
});
|
||||
});
|
||||
eventStore.on(FEATURE_REVIVED, ({ featureName, project }) => {
|
||||
featureToggleUpdateTotal
|
||||
.labels(featureName, project, 'n/a', 'n/a')
|
||||
.inc();
|
||||
featureToggleUpdateTotal.increment({
|
||||
toggle: featureName,
|
||||
project,
|
||||
environment: 'n/a',
|
||||
environmentType: 'n/a',
|
||||
});
|
||||
});
|
||||
|
||||
eventBus.on(CLIENT_METRICS, (m: ValidatedClientMetrics) => {
|
||||
for (const entry of Object.entries(m.bucket.toggles)) {
|
||||
featureToggleUsageTotal
|
||||
.labels(entry[0], 'true', m.appName)
|
||||
.inc(entry[1].yes);
|
||||
featureToggleUsageTotal
|
||||
.labels(entry[0], 'false', m.appName)
|
||||
.inc(entry[1].no);
|
||||
featureToggleUsageTotal.increment(
|
||||
{
|
||||
toggle: entry[0],
|
||||
active: 'true',
|
||||
appName: m.appName,
|
||||
},
|
||||
entry[1].yes,
|
||||
);
|
||||
featureToggleUsageTotal.increment(
|
||||
{
|
||||
toggle: entry[0],
|
||||
active: 'false',
|
||||
appName: m.appName,
|
||||
},
|
||||
entry[1].no,
|
||||
);
|
||||
}
|
||||
});
|
||||
eventStore.on(CLIENT_REGISTER, (m) => {
|
||||
if (m.sdkVersion && m.sdkVersion.indexOf(':') > -1) {
|
||||
const [sdkName, sdkVersion] = m.sdkVersion.split(':');
|
||||
clientSdkVersionUsage.labels(sdkName, sdkVersion).inc();
|
||||
clientSdkVersionUsage.increment({
|
||||
sdk_name: sdkName,
|
||||
sdk_version: sdkVersion,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -495,29 +544,29 @@ export default class MetricsMonitor {
|
||||
|
||||
configureDbMetrics(db: Knex, eventBus: EventEmitter): void {
|
||||
if (db?.client) {
|
||||
const dbPoolMin = new client.Gauge({
|
||||
const dbPoolMin = createGauge({
|
||||
name: 'db_pool_min',
|
||||
help: 'Minimum DB pool size',
|
||||
});
|
||||
dbPoolMin.set(db.client.pool.min);
|
||||
const dbPoolMax = new client.Gauge({
|
||||
const dbPoolMax = createGauge({
|
||||
name: 'db_pool_max',
|
||||
help: 'Maximum DB pool size',
|
||||
});
|
||||
dbPoolMax.set(db.client.pool.max);
|
||||
const dbPoolFree = new client.Gauge({
|
||||
const dbPoolFree = createGauge({
|
||||
name: 'db_pool_free',
|
||||
help: 'Current free connections in DB pool',
|
||||
});
|
||||
const dbPoolUsed = new client.Gauge({
|
||||
const dbPoolUsed = createGauge({
|
||||
name: 'db_pool_used',
|
||||
help: 'Current connections in use in DB pool',
|
||||
});
|
||||
const dbPoolPendingCreates = new client.Gauge({
|
||||
const dbPoolPendingCreates = createGauge({
|
||||
name: 'db_pool_pending_creates',
|
||||
help: 'how many asynchronous create calls are running in DB pool',
|
||||
});
|
||||
const dbPoolPendingAcquires = new client.Gauge({
|
||||
const dbPoolPendingAcquires = createGauge({
|
||||
name: 'db_pool_pending_acquires',
|
||||
help: 'how many acquires are waiting for a resource to be released in DB pool',
|
||||
});
|
||||
|
52
src/lib/util/metrics/createCounter.ts
Normal file
52
src/lib/util/metrics/createCounter.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { Counter, CounterConfiguration } from 'prom-client';
|
||||
|
||||
/**
|
||||
* Creates a wrapped instance of prom-client's Counter, overriding some of its methods for enhanced functionality and type-safety.
|
||||
*
|
||||
* @param options - The configuration options for the Counter, as defined in prom-client's CounterConfiguration.
|
||||
* See prom-client documentation for detailed options: https://github.com/siimon/prom-client#counter
|
||||
* @returns An object containing the wrapped Counter instance and custom methods.
|
||||
*/
|
||||
export const createCounter = <T extends string>(
|
||||
options: CounterConfiguration<T>,
|
||||
) => {
|
||||
/**
|
||||
* The underlying instance of prom-client's Counter.
|
||||
*/
|
||||
const counter = new Counter(options);
|
||||
|
||||
/**
|
||||
* Applies given labels to the counter. Labels are key-value pairs.
|
||||
* This method wraps the original Counter's labels method for additional type-safety, requiring all configured labels to be specified.
|
||||
*
|
||||
* @param labels - An object where keys are label names and values are the label values.
|
||||
* @returns The Counter instance with the applied labels, allowing for method chaining.
|
||||
*/
|
||||
const labels = (labels: Record<T, string | number>) =>
|
||||
counter.labels(labels);
|
||||
|
||||
/**
|
||||
* Increments the counter by a specified value or by 1 if no value is provided.
|
||||
* Wraps the original Counter's inc method.
|
||||
*
|
||||
* @param value - (Optional) The value to increment the counter by. If not provided, defaults to 1.
|
||||
*/
|
||||
const inc = (value?: number | undefined) => counter.inc(value);
|
||||
|
||||
/**
|
||||
* A convenience method that combines setting labels and incrementing the counter.
|
||||
* Useful for incrementing with labels in a single call.
|
||||
*
|
||||
* @param labels - An object where keys are label names and values are the label values.
|
||||
* @param value - (Optional) The value to increment the counter by. If not provided, defaults to 1.
|
||||
*/
|
||||
const increment = (labels: Record<T, string | number>, value?: number) =>
|
||||
counter.labels(labels).inc(value);
|
||||
|
||||
return {
|
||||
counter,
|
||||
labels,
|
||||
inc,
|
||||
increment,
|
||||
};
|
||||
};
|
47
src/lib/util/metrics/createGauge.ts
Normal file
47
src/lib/util/metrics/createGauge.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { Gauge, GaugeConfiguration } from 'prom-client';
|
||||
|
||||
/**
|
||||
* Creates a wrapped instance of prom-client's Gauge, overriding some of its methods for enhanced functionality and type-safety.
|
||||
*
|
||||
* @param options - The configuration options for the Gauge, as defined in prom-client's GaugeConfiguration.
|
||||
* See prom-client documentation for detailed options: https://github.com/siimon/prom-client#gauge
|
||||
* @returns An object containing the wrapped Gauge instance and custom methods.
|
||||
*/
|
||||
export const createGauge = <T extends string>(
|
||||
options: GaugeConfiguration<T>,
|
||||
) => {
|
||||
/**
|
||||
* The underlying instance of prom-client's Gauge.
|
||||
*/
|
||||
const gauge = new Gauge(options);
|
||||
|
||||
/**
|
||||
* Applies given labels to the gauge. Labels are key-value pairs.
|
||||
* This method wraps the original Gauge's labels method for additional type-safety, requiring all configured labels to be specified.
|
||||
*
|
||||
* @param labels - An object where keys are label names and values are the label values.
|
||||
* @returns The Gauge instance with the applied labels, allowing for method chaining.
|
||||
*/
|
||||
const labels = (labels: Record<T, string | number>) => gauge.labels(labels);
|
||||
|
||||
/**
|
||||
* Resets the gauge value.
|
||||
* Wraps the original Gauge's reset method.
|
||||
*/
|
||||
const reset = () => gauge.reset();
|
||||
|
||||
/**
|
||||
* Sets the gauge to a specified value.
|
||||
* Wraps the original Gauge's set method.
|
||||
*
|
||||
* @param value - The value to set the gauge to.
|
||||
*/
|
||||
const set = (value: number) => gauge.set(value);
|
||||
|
||||
return {
|
||||
gauge,
|
||||
labels,
|
||||
reset,
|
||||
set,
|
||||
};
|
||||
};
|
41
src/lib/util/metrics/createSummary.ts
Normal file
41
src/lib/util/metrics/createSummary.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Summary, SummaryConfiguration } from 'prom-client';
|
||||
|
||||
/**
|
||||
* Creates a wrapped instance of prom-client's Summary, overriding some of its methods for enhanced functionality and type-safety.
|
||||
*
|
||||
* @param options - The configuration options for the Summary, as defined in prom-client's SummaryConfiguration.
|
||||
* See prom-client documentation for detailed options: https://github.com/siimon/prom-client#summary
|
||||
* @returns An object containing the wrapped Summary instance and custom methods.
|
||||
*/
|
||||
export const createSummary = <T extends string>(
|
||||
options: SummaryConfiguration<T>,
|
||||
) => {
|
||||
/**
|
||||
* The underlying instance of prom-client's Summary.
|
||||
*/
|
||||
const summary = new Summary(options);
|
||||
|
||||
/**
|
||||
* Applies given labels to the summary. Labels are key-value pairs.
|
||||
* This method wraps the original Summary's labels method for additional type-safety, requiring all configured labels to be specified.
|
||||
*
|
||||
* @param labels - An object where keys are label names and values are the label values.
|
||||
* @returns The Summary instance with the applied labels, allowing for method chaining.
|
||||
*/
|
||||
const labels = (labels: Record<T, string | number>) =>
|
||||
summary.labels(labels);
|
||||
|
||||
/**
|
||||
* Observes a value in the summary.
|
||||
* Wraps the original Summary's observe method.
|
||||
*
|
||||
* @param value - The value to observe.
|
||||
*/
|
||||
const observe = (value: number) => summary.observe(value);
|
||||
|
||||
return {
|
||||
summary,
|
||||
labels,
|
||||
observe,
|
||||
};
|
||||
};
|
3
src/lib/util/metrics/index.ts
Normal file
3
src/lib/util/metrics/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './createCounter';
|
||||
export * from './createGauge';
|
||||
export * from './createSummary';
|
Loading…
Reference in New Issue
Block a user