Skip to content

Commit

Permalink
Added utilities for creating custom prometheus metrics (TryGhost#21614)
Browse files Browse the repository at this point in the history
ref
https://linear.app/ghost/issue/ENG-1771/add-utility-functions-to-easily-create-custom-metrics

- Currently adding custom metrics to our prometheus client requires you
to directly access the `prometheusClient.client` to create the metrics
- This isn't super convenient, as you then have to either keep the
metric in a local variable, or manually get it from the
`prometheusClient.client.register`
- This commit exposes some utility functions for registering metrics on
the `prometheusClient` class, and for retrieving metrics that have
already been registered
  • Loading branch information
cmraible authored Nov 14, 2024
1 parent 9da4aa3 commit 6d9ea91
Show file tree
Hide file tree
Showing 2 changed files with 545 additions and 5 deletions.
116 changes: 114 additions & 2 deletions ghost/prometheus-metrics/src/PrometheusClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Request, Response} from 'express';
import client from 'prom-client';
import type {Metric, MetricObjectWithValues, MetricValue} from 'prom-client';
import type {Knex} from 'knex';
import logging from '@tryghost/logging';

Expand Down Expand Up @@ -112,19 +113,130 @@ export class PrometheusClient {
}

/**
* Returns the metrics from the registry
* Returns the metrics from the registry as a string
*/
async getMetrics() {
async getMetrics(): Promise<string> {
return this.client.register.metrics();
}

/**
* Returns the metrics from the registry as a JSON object
*
* Particularly useful for testing
*/
async getMetricsAsJSON(): Promise<object[]> {
return this.client.register.getMetricsAsJSON();
}

async getMetricsAsArray(): Promise<object[]> {
return this.client.register.getMetricsAsArray();
}

/**
* Returns the content type for the metrics
*/
getContentType() {
return this.client.register.contentType;
}

/**
* Returns a single metric from the registry
* @param name - The name of the metric
* @returns The metric
*/
getMetric(name: string): Metric | undefined {
if (!name.startsWith(this.prefix)) {
name = `${this.prefix}${name}`;
}
return this.client.register.getSingleMetric(name);
}

/**
* Returns the metric object of a single metric, if it exists
* @param name - The name of the metric
* @returns The values of the metric
*/
async getMetricObject(name: string): Promise<MetricObjectWithValues<MetricValue<string>> | undefined> {
const metric = this.getMetric(name);
if (!metric) {
return undefined;
}
return await metric.get();
}

async getMetricValues(name: string): Promise<MetricValue<string>[] | undefined> {
const metricObject = await this.getMetricObject(name);
if (!metricObject) {
return undefined;
}
return metricObject.values;
}

/**
*
*/

/**
* Registers a counter metric
* @param name - The name of the metric
* @param help - The help text for the metric
* @returns The counter metric
*/
registerCounter({name, help}: {name: string, help: string}): client.Counter {
return new this.client.Counter({
name: `${this.prefix}${name}`,
help
});
}

/**
* Registers a gauge metric
* @param name - The name of the metric
* @param help - The help text for the metric
* @param collect - The collect function to use for the gauge
* @returns The gauge metric
*/
registerGauge({name, help, collect}: {name: string, help: string, collect?: () => void}): client.Gauge {
return new this.client.Gauge({
name: `${this.prefix}${name}`,
help,
collect
});
}

/**
* Registers a summary metric
* @param name - The name of the metric
* @param help - The help text for the metric
* @param percentiles - The percentiles to calculate for the summary
* @param collect - The collect function to use for the summary
* @returns The summary metric
*/
registerSummary({name, help, percentiles, collect}: {name: string, help: string, percentiles?: number[], collect?: () => void}): client.Summary {
return new this.client.Summary({
name: `${this.prefix}${name}`,
help,
percentiles: percentiles || [0.5, 0.9, 0.99],
collect
});
}

/**
* Registers a histogram metric
* @param name - The name of the metric
* @param help - The help text for the metric
* @param buckets - The buckets to calculate for the histogram
* @param collect - The collect function to use for the histogram
* @returns The histogram metric
*/
registerHistogram({name, help, buckets}: {name: string, help: string, buckets: number[], collect?: () => void}): client.Histogram {
return new this.client.Histogram({
name: `${this.prefix}${name}`,
help,
buckets: buckets
});
}

// Utility functions for creating custom metrics

/**
Expand Down
Loading

0 comments on commit 6d9ea91

Please sign in to comment.