78 lines
2.1 KiB
TypeScript
78 lines
2.1 KiB
TypeScript
|
import type { Context } from 'hono'
|
||
|
import { createMiddleware } from 'hono/factory'
|
||
|
import type { DefaultMetricsCollectorConfiguration, RegistryContentType } from 'prom-client'
|
||
|
import { Registry, collectDefaultMetrics as promCollectDefaultMetrics } from 'prom-client'
|
||
|
import { type MetricOptions, type CustomMetricsOptions, createStandardMetrics } from './standardMetrics'
|
||
|
|
||
|
interface PrometheusOptions {
|
||
|
registry?: Registry;
|
||
|
collectDefaultMetrics?: boolean | DefaultMetricsCollectorConfiguration<RegistryContentType>;
|
||
|
prefix?: string;
|
||
|
metricOptions?: Omit<CustomMetricsOptions, 'prefix' | 'register'>;
|
||
|
}
|
||
|
|
||
|
const evaluateCustomLabels = (
|
||
|
customLabels: MetricOptions['customLabels'],
|
||
|
context: Context,
|
||
|
) => {
|
||
|
const labels: Record<string, string> = {}
|
||
|
|
||
|
for (const [key, fn] of Object.entries(customLabels ?? {})) {
|
||
|
labels[key] = fn(context)
|
||
|
}
|
||
|
|
||
|
return labels
|
||
|
}
|
||
|
|
||
|
export const prometheus = (options?: PrometheusOptions) => {
|
||
|
const {
|
||
|
registry = new Registry(),
|
||
|
collectDefaultMetrics = false,
|
||
|
prefix = '',
|
||
|
metricOptions,
|
||
|
} = options ?? {}
|
||
|
|
||
|
if (collectDefaultMetrics) {
|
||
|
promCollectDefaultMetrics({
|
||
|
prefix,
|
||
|
register: registry,
|
||
|
...(typeof collectDefaultMetrics === 'object' && collectDefaultMetrics)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
const metrics = createStandardMetrics({
|
||
|
prefix,
|
||
|
registry,
|
||
|
customOptions: metricOptions,
|
||
|
})
|
||
|
|
||
|
return {
|
||
|
printMetrics: async (c: Context) => c.text(await registry.metrics()),
|
||
|
registerMetrics: createMiddleware(async (c, next) => {
|
||
|
const timer = metrics.requestDuration?.startTimer()
|
||
|
|
||
|
try {
|
||
|
await next()
|
||
|
|
||
|
} finally {
|
||
|
const commonLabels = {
|
||
|
method: c.req.method,
|
||
|
route: c.req.routePath,
|
||
|
status: c.res.status.toString(),
|
||
|
ok: String(c.res.ok),
|
||
|
}
|
||
|
|
||
|
timer?.({
|
||
|
...commonLabels,
|
||
|
...evaluateCustomLabels(metricOptions?.requestDuration?.customLabels, c)
|
||
|
})
|
||
|
|
||
|
metrics.requestsTotal?.inc({
|
||
|
...commonLabels,
|
||
|
...evaluateCustomLabels(metricOptions?.requestsTotal?.customLabels, c)
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|