import { ApiInternalServerErrorException } from "@components/api-exceptions"
import Elysia from "elysia"
import client, { type Metric } from "prom-client"
* Builder class for creating and configuring Prometheus metrics
* const metricsBuilder = new MetricsBuilder()
* .withoutDefaultMetrics(false)
export class MetricsBuilder {
private register: client.Registry
private defaultMetrics = true
this.register = new client.Registry()
* Sets the prefix for all metrics
* @param prefix - The prefix to add to all metric names
* @returns The builder instance for method chaining
withPrefix(prefix: string) {
* Configures whether to collect default metrics
* @param defaultMetrics - If false, disables default metrics collection
* @returns The builder instance for method chaining
withDefaultMetrics(newVal: boolean) {
this.defaultMetrics = newVal
* Builds and returns the metrics registry with the configured settings
* @returns An object containing registry methods and properties
if (this.defaultMetrics) {
client.collectDefaultMetrics({
contentType: this.register.contentType,
registerMetrics: this.register.registerMetric.bind(this.register),
metrics: this.register.metrics.bind(this.register),
getMetric: this.register.getSingleMetric.bind(this.register),
* Factory function to create an Elysia plugin with metrics registry
* @param defaultMetrics - Whether to collect default metrics
* @param prefix - Prefix for metric names
* @returns Elysia plugin with configured metrics registry
export const metricsFactory = (defaultMetrics = true, prefix = "app_") =>
new MetricsBuilder().withPrefix(prefix).withDefaultMetrics(defaultMetrics).build(),
* Factory function to create an Elysia plugin with a pre-configured metrics registry
* @param metricsBuilder - A built metrics registry instance from MetricsBuilder
* @returns Elysia plugin decorated with the provided metrics registry
export const globalMetricsFactory = (metricsBuilder: ReturnType<typeof MetricsBuilder.prototype.build>) =>
new Elysia().decorate("registry", metricsBuilder)
* Creates an Elysia plugin that registers and retrieves a specific metric
* @param metric - The Prometheus metric to register
* @returns Elysia plugin that provides access to the metric
* @throws Error if metrics registry is not found
export const getMetric = <T extends Metric>(metric: T) =>
new Elysia().derive({ as: "scoped" }, async (context) => {
// biome-ignore lint/suspicious/noExplicitAny: Required for context type
const registry = (context as any).registry as ReturnType<typeof MetricsBuilder.prototype.build>
const metricValue = await metric.get()
const registeredMetric = registry.getMetric(metricValue.name)
registry.registerMetrics(metric)
[metricValue.name]: metric,
throw new ApiInternalServerErrorException("Metric registry not found")
* Creates an Elysia plugin that provides access to the metrics registry
* @returns Elysia plugin with registry access
* @throws Error if metrics registry is not found
export const getRegistry = () =>
new Elysia().derive({ as: "scoped" }, async (context) => {
// biome-ignore lint/suspicious/noExplicitAny: Required for context type
const registry = (context as any).registry as ReturnType<typeof MetricsBuilder.prototype.build>
throw new ApiInternalServerErrorException("Metrics registry not found")