Memoized renderering (#37)

Pre-render metrics on discovery once and then reuse rendered response.
This commit is contained in:
Lars Strojny 2022-11-24 19:35:02 +01:00 committed by GitHub
parent 565f423dd9
commit 65304798de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 19 additions and 18 deletions

View file

@ -28,5 +28,5 @@ export interface HttpServer {
onMetrics(): HttpResponse
onNotFound(): HttpResponse
onError(error: Error): HttpResponse
updateMetrics(metrics: Metric[]): void
onMetricsDiscovery(metrics: Metric[]): void
}

View file

@ -48,7 +48,7 @@ export class PrometheusExporterPlatform implements IndependentPlatformPlugin {
discover({ log: this.log, config: this.config })
.then((devices) => {
const metrics = aggregate(devices, new Date())
this.httpServer.updateMetrics(metrics)
this.httpServer.onMetricsDiscovery(metrics)
this.log.debug('HAP discovery completed, %d metrics discovered', metrics.length)
this.startHapDiscovery()
})

View file

@ -44,13 +44,17 @@ function headers(contentType: string, headers: Record<string, string> = {}): Rec
}
export class PrometheusServer implements HttpServer {
private metricsInitialized = false
private metrics: Metric[] = []
private metricsDiscovered = false
private metricsResponse = ''
constructor(public readonly config: HttpConfig, public readonly log: Logger | undefined = undefined) {}
constructor(
public readonly config: HttpConfig,
public readonly log: Logger | undefined = undefined,
private readonly renderer: MetricsRenderer = new MetricsRenderer(config.prefix),
) {}
onRequest(): HttpResponse | undefined {
if (!this.metricsInitialized) {
if (!this.metricsDiscovered) {
return {
statusCode: 503,
headers: headers(textContentType, { 'Retry-After': String(retryAfterWhileDiscovery) }),
@ -60,13 +64,10 @@ export class PrometheusServer implements HttpServer {
}
onMetrics(): HttpResponse {
const renderer = new MetricsRenderer(this.config.prefix)
const metrics = this.metrics.map((metric) => renderer.render(metric)).join('\n')
return {
statusCode: 200,
headers: headers(metricsContentType),
body: metrics,
body: this.metricsResponse,
}
}
@ -86,9 +87,9 @@ export class PrometheusServer implements HttpServer {
}
}
updateMetrics(metrics: Metric[]): void {
this.metrics = metrics
this.metricsInitialized = true
onMetricsDiscovery(metrics: Metric[]): void {
this.metricsResponse = metrics.map((metric) => this.renderer.render(metric)).join('\n')
this.metricsDiscovered = true
}
}

View file

@ -46,7 +46,7 @@ describe('Fastify HTTP adapter', () => {
test('Serves 404 on / when metrics are available', () => {
const testServer = createTestServer()
testServer.prometheus.updateMetrics([])
testServer.prometheus.onMetricsDiscovery([])
return request(testServer.http)
.get('/')
@ -58,7 +58,7 @@ describe('Fastify HTTP adapter', () => {
test('Serves metrics', () => {
const testServer = createTestServer()
const timestamp = new Date('2020-01-01 00:00:00 UTC')
testServer.prometheus.updateMetrics([
testServer.prometheus.onMetricsDiscovery([
new Metric('metric', 0.1, timestamp, { name: 'metric' }),
new Metric('total_something', 100, timestamp, { name: 'counter' }),
])
@ -79,7 +79,7 @@ describe('Fastify HTTP adapter', () => {
test('Basic auth denied without user', () => {
const testServer = createTestServerWithBasicAuth({ joanna: secretAsBcrypt })
testServer.prometheus.updateMetrics([])
testServer.prometheus.onMetricsDiscovery([])
return request(testServer.http)
.get('/metrics')
@ -90,7 +90,7 @@ describe('Fastify HTTP adapter', () => {
test('Basic auth denied with incorrect user', () => {
const testServer = createTestServerWithBasicAuth({ joanna: secretAsBcrypt })
testServer.prometheus.updateMetrics([])
testServer.prometheus.onMetricsDiscovery([])
return request(testServer.http)
.get('/metrics')
@ -103,7 +103,7 @@ describe('Fastify HTTP adapter', () => {
test('Basic auth grants access', () => {
const testServer = createTestServerWithBasicAuth({ joanna: secretAsBcrypt })
const timestamp = new Date('2020-01-01 00:00:00 UTC')
testServer.prometheus.updateMetrics([
testServer.prometheus.onMetricsDiscovery([
new Metric('metric', 0.1, timestamp, { name: 'metric' }),
new Metric('total_something', 100, timestamp, { name: 'counter' }),
])