Select Git revision
-
Sigmund, Dominik authoredSigmund, Dominik authored
index.ts 4.24 KiB
import * as express from 'express'
export interface Options {
ignore: string[]
disableRouteCounter: boolean
disableErrorCounter: boolean
disableDurationCounter: boolean
disableDefaultMetrics: boolean
}
export interface CustomMetric {
name: string
help: string
labelNames: string[]
}
export class Metrics {
public readonly _ignore: string[]
public readonly _disableRouteCounter: boolean
public readonly _disableErrorCounter: boolean
public readonly _disableDurationCounter: boolean
public readonly _disableDefaultMetrics: boolean
public readonly _client: any
public readonly _httpRequestDurationMicroseconds: any
public readonly _numOfRequests: any
public readonly _numOfErrors: any
public readonly _customMetrics: any
constructor (options: Partial<Options> = {}) {
this._client = require('prom-client')
this._customMetrics = {}
if (typeof options.ignore !== 'undefined') {
this._ignore = options.ignore
this._ignore.push('/_metrics')
this._ignore.push('/favicon.ico')
} else {
this._ignore = ['/_metrics', '/favicon.ico']
}
if (typeof options.disableRouteCounter !== 'undefined') {
this._disableRouteCounter = options.disableRouteCounter
} else {
this._disableRouteCounter = false
}
if (typeof options.disableErrorCounter !== 'undefined') {
this._disableErrorCounter = options.disableErrorCounter
} else {
this._disableErrorCounter = false
}
if (typeof options.disableDurationCounter !== 'undefined') {
this._disableDurationCounter = options.disableDurationCounter
} else {
this._disableDurationCounter = false
}
if (typeof options.disableDefaultMetrics !== 'undefined') {
this._disableDefaultMetrics = options.disableDefaultMetrics
} else {
this._disableDefaultMetrics = false
}
if (!this._disableDefaultMetrics) {
this._client.collectDefaultMetrics()
}
if (!this._disableErrorCounter) {
this._numOfErrors = new this._client.Counter({
name: 'numOfErrors',
help: 'Number of errors',
labelNames: ['error']
})
}
if (!this._disableRouteCounter) {
this._numOfRequests = new this._client.Counter({
name: 'numOfRequests',
help: 'Number of requests made to a route',
labelNames: ['route']
})
}
if (!this._disableDurationCounter) {
this._httpRequestDurationMicroseconds = new this._client.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]
})
}
}
public addCustomMetric = (options: CustomMetric): void => {
this._customMetrics[options.name] = new this._client.Gauge({
name: options.name,
help: options.help,
labelNames: options.labelNames
})
}
public incCustomMetric = (name: string, label: string, value: string): void => {
const inc: any = {}
inc[label] = value
this._customMetrics[name].inc(inc)
}
public decCustomMetric = (name: string, label: string, value: string): void => {
const dec: any = {}
dec[label] = value
this._customMetrics[name].dec(dec)
}
public collect = (req: express.Request, res: express.Response, next: express.NextFunction): void => {
res.locals.startEpoch = Date.now()
res.on('finish', () => {
if (!this._ignore.includes(req.originalUrl)) {
const responseTimeInMs = Date.now() - res.locals.startEpoch
if (!this._disableDurationCounter) {
this._httpRequestDurationMicroseconds
.labels(req.method, req.originalUrl, res.statusCode.toString())
.observe(responseTimeInMs)
}
if (!this._disableRouteCounter) {
this._numOfRequests.inc({ route: req.originalUrl })
}
if (res.statusCode >= 400) {
if (!this._disableErrorCounter) {
this._numOfErrors.inc({ error: res.statusCode })
}
}
}
})
next()
}
public endpoint = (req: express.Request, res: express.Response): void => {
res.set('Content-Type', this._client.register.contentType)
res.status(200)
res.end(this._client.register.metrics())
}
}
export default Metrics