import * as express from 'express' import Prometheus = require('prom-client') export class Metrics { private readonly _options: any public readonly _httpRequestDurationMicroseconds: any public readonly _numOfRequests: any public readonly _numOfErrors: any constructor (options: any) { this._options = options this._httpRequestDurationMicroseconds = new Prometheus.Histogram({ name: 'http_request_duration_ms', help: 'Duration of HTTP requests in ms', labelNames: ['method', 'route', 'code'], buckets: [0.10, 5, 15, 50, 100, 200, 300, 400, 500] }) this._numOfRequests = new Prometheus.Counter({ name: 'numOfRequests', help: 'Number of requests made to a route', labelNames: ['route'] }) this._numOfErrors = new Prometheus.Counter({ name: 'numOfErrors', help: 'Number of errors', labelNames: ['error'] }) // TODO: config: ignore routes, disable metrics } public start (req: express.Request, res: express.Response, next: express.NextFunction): void { res.locals.startEpoch = Date.now() res.on('finish', () => { if (req.originalUrl !== '/_metrics' && req.originalUrl !== './favicon.ico') { const responseTimeInMs = Date.now() - res.locals.startEpoch this._httpRequestDurationMicroseconds .labels(req.method, req.originalUrl, res.statusCode.toString()) .observe(responseTimeInMs) this._numOfRequests.inc({ route: req.originalUrl }) if (res.statusCode >= 400) { this._numOfErrors.inc({ error: res.statusCode }) } } }) next() } public endpoint (req: express.Request, res: express.Response): void { res.set('Content-Type', Prometheus.register.contentType) res.end(Prometheus.register.metrics()) } } export default Metrics