Skip to content
Snippets Groups Projects

Master to main

Merged Sigmund, Dominik requested to merge master into main
1 file
+ 1
0
Compare changes
  • Side-by-side
  • Inline
src/index.ts 0 → 100755
+ 167
0
import * as express from 'express'
export interface Options {
ignore: string[]
disableRouteCounter: boolean
disableErrorCounter: boolean
disableDurationCounter: boolean
disableDefaultMetrics: boolean
disableClientCounter: boolean
}
export interface CustomMetric {
name: string
help: string
labelNames?: string[]
}
export enum MetricType {
GAUGE,
COUNTER,
HISTOGRAM,
SUMMARY
}
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 _disableClientCounter: boolean
public readonly _client: any
public readonly _httpRequestDurationMicroseconds: any
public readonly _numOfRequests: any
public readonly _numOfErrors: any
public readonly _clients: 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 (typeof options.disableClientCounter !== 'undefined') {
this._disableClientCounter = options.disableClientCounter
} else {
this._disableClientCounter = false
}
if (!this._disableDefaultMetrics) {
this._client.collectDefaultMetrics()
}
if (!this._disableErrorCounter) {
this._numOfErrors = new this._client.Counter({
name: 'http_errors_total',
help: 'Number of errors',
labelNames: ['error']
})
}
if (!this._disableRouteCounter) {
this._numOfRequests = new this._client.Counter({
name: 'http_requests_total',
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]
})
}
if (!this._disableClientCounter) {
this._clients = new this._client.Counter({
name: 'http_clients_total',
help: 'Hostname and IP for Client with count of connections',
labelNames: ['hostname', 'ip']
})
}
}
public addCustomMetric = (options: CustomMetric, type: MetricType): void => {
switch (type) {
case MetricType.COUNTER:
this.customMetrics[options.name] = new this._client.Counter(options)
break
case MetricType.GAUGE:
this.customMetrics[options.name] = new this._client.Gauge(options)
break
case MetricType.HISTOGRAM:
this.customMetrics[options.name] = new this._client.Histogram(options)
break
case MetricType.SUMMARY:
this.customMetrics[options.name] = new this._client.Summary(options)
break
default:
break
}
}
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 (!this._disableClientCounter) {
this._clients.inc({ hostname: req.hostname, ip: req.ip })
}
if (res.statusCode >= 400) {
if (!this._disableErrorCounter) {
this._numOfErrors.inc({ error: res.statusCode })
}
}
}
})
next()
}
public endpoint = async (req: express.Request, res: express.Response): Promise<void> => {
res.set('Content-Type', this._client.register.contentType)
res.status(200)
res.end(await this._client.register.metrics())
}
public resetMetrics = (): void => {
this._client.register.resetMetrics()
}
}
export default Metrics
Loading