185 lines
5.3 KiB
TypeScript
185 lines
5.3 KiB
TypeScript
import { Hono } from 'hono'
|
|
import type { Histogram } from 'prom-client'
|
|
import { Registry } from 'prom-client'
|
|
import { prometheus } from './index'
|
|
|
|
describe('Prometheus middleware', () => {
|
|
const app = new Hono()
|
|
const registry = new Registry()
|
|
|
|
app.use(
|
|
'*',
|
|
prometheus({
|
|
registry,
|
|
}).registerMetrics
|
|
)
|
|
|
|
app.get('/', (c) => c.text('hello'))
|
|
app.get('/user/:id', (c) => c.text(c.req.param('id')))
|
|
|
|
beforeEach(() => registry.resetMetrics())
|
|
|
|
describe('configuration', () => {
|
|
it('prefix - adds the provided prefix to the metric names', async () => {
|
|
const app = new Hono()
|
|
const registry = new Registry()
|
|
|
|
app.use(
|
|
'*',
|
|
prometheus({
|
|
registry,
|
|
prefix: 'myprefix_',
|
|
}).registerMetrics
|
|
)
|
|
|
|
expect(await registry.metrics()).toMatchInlineSnapshot(`
|
|
"# HELP myprefix_http_request_duration_seconds Duration of HTTP requests in seconds
|
|
# TYPE myprefix_http_request_duration_seconds histogram
|
|
|
|
# HELP myprefix_http_requests_total Total number of HTTP requests
|
|
# TYPE myprefix_http_requests_total counter
|
|
"
|
|
`)
|
|
})
|
|
|
|
it('customLabels - adds custom labels to metrics', async () => {
|
|
const app = new Hono()
|
|
const registry = new Registry()
|
|
|
|
app.use(
|
|
'*',
|
|
prometheus({
|
|
registry,
|
|
metricOptions: {
|
|
requestsTotal: {
|
|
customLabels: {
|
|
id: (c) => c.req.query('id') ?? 'unknown',
|
|
contentType: (c) => c.res.headers.get('content-type') ?? 'unknown',
|
|
},
|
|
},
|
|
},
|
|
}).registerMetrics
|
|
)
|
|
|
|
app.get('/', (c) => c.text('hello'))
|
|
|
|
await app.request('http://localhost/?id=123')
|
|
|
|
expect(await registry.getSingleMetricAsString('http_requests_total')).toMatchInlineSnapshot(`
|
|
"# HELP http_requests_total Total number of HTTP requests
|
|
# TYPE http_requests_total counter
|
|
http_requests_total{method="GET",route="/",status="200",ok="true",id="123",contentType="text/plain;charset=UTF-8"} 1"
|
|
`)
|
|
})
|
|
})
|
|
|
|
describe('metrics', () => {
|
|
describe('http_requests_total', () => {
|
|
it('increments the http_requests_total metric with the correct labels on successful responses', async () => {
|
|
await app.request('http://localhost/')
|
|
|
|
const { values } = await registry.getSingleMetric('http_requests_total')!.get()!
|
|
|
|
expect(values).toEqual([
|
|
{
|
|
labels: {
|
|
method: 'GET',
|
|
route: '/',
|
|
status: '200',
|
|
ok: 'true',
|
|
},
|
|
value: 1,
|
|
},
|
|
])
|
|
})
|
|
|
|
it('increments the http_requests_total metric with the correct labels on errors', async () => {
|
|
await app.request('http://localhost/notfound')
|
|
|
|
const { values } = await registry.getSingleMetric('http_requests_total')!.get()!
|
|
|
|
expect(values).toEqual([
|
|
{
|
|
labels: {
|
|
method: 'GET',
|
|
route: '/*',
|
|
status: '404',
|
|
ok: 'false',
|
|
},
|
|
value: 1,
|
|
},
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('http_requests_duration', () => {
|
|
it('updates the http_requests_duration metric with the correct labels on successful responses', async () => {
|
|
await app.request('http://localhost/')
|
|
|
|
const { values } = await (registry.getSingleMetric(
|
|
'http_request_duration_seconds'
|
|
) as Histogram)!.get()!
|
|
|
|
const countMetric = values.find(
|
|
(v) =>
|
|
v.metricName === 'http_request_duration_seconds_count' &&
|
|
v.labels.method === 'GET' &&
|
|
v.labels.route === '/' &&
|
|
v.labels.status === '200'
|
|
)
|
|
|
|
expect(countMetric?.value).toBe(1)
|
|
})
|
|
|
|
it('updates the http_requests_duration metric with the correct labels on errors', async () => {
|
|
await app.request('http://localhost/notfound')
|
|
|
|
const { values } = await (registry.getSingleMetric(
|
|
'http_request_duration_seconds'
|
|
) as Histogram)!.get()!
|
|
|
|
const countMetric = values.find(
|
|
(v) =>
|
|
v.metricName === 'http_request_duration_seconds_count' &&
|
|
v.labels.method === 'GET' &&
|
|
v.labels.route === '/*' &&
|
|
v.labels.status === '404'
|
|
)
|
|
|
|
expect(countMetric?.value).toBe(1)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('metrics endpoint', () => {
|
|
it('returns the metrics in the prometheus string format on the /metrics endpoint', async () => {
|
|
const app = new Hono()
|
|
const registry = new Registry()
|
|
|
|
const { printMetrics, registerMetrics } = prometheus({
|
|
registry,
|
|
metricOptions: {
|
|
requestDuration: {
|
|
disabled: true, // Disable duration metrics to make the test result more predictable
|
|
},
|
|
},
|
|
})
|
|
|
|
app.use('*', registerMetrics)
|
|
app.get('/', (c) => c.text('hello'))
|
|
app.get('/metrics', printMetrics)
|
|
|
|
await app.request('http://localhost/')
|
|
|
|
const response = await app.request('http://localhost/metrics')
|
|
|
|
expect(await response.text()).toMatchInlineSnapshot(`
|
|
"# HELP http_requests_total Total number of HTTP requests
|
|
# TYPE http_requests_total counter
|
|
http_requests_total{method="GET",route="/",status="200",ok="true"} 1
|
|
"
|
|
`)
|
|
})
|
|
})
|
|
})
|