Skip to content
Snippets Groups Projects
Commit 45d58d0b authored by Sigmund, Dominik's avatar Sigmund, Dominik
Browse files

Basic Tests

parent c158e070
No related branches found
No related tags found
1 merge request!1Master to main
...@@ -20,7 +20,7 @@ A small express middleware to get base metrics for any node.js app. ...@@ -20,7 +20,7 @@ A small express middleware to get base metrics for any node.js app.
Note: The options Part may be omitted, as all parts are optional. Note: The options Part may be omitted, as all parts are optional.
Before your Routes: Before your Routes:
`router.use(metrics.start.bind(metrics))` `router.use(metrics.collect)`
And to enable the *_metrics*-Endpoint: And to enable the *_metrics*-Endpoint:
`router.get('/_metrics', metrics.endpoint)` `router.get('/_metrics', metrics.endpoint)`
......
# TODO # TODO
- disable default metrics
- tests - tests
- get to gitlab-server - mutation tests
- publish to npm - publish to npm
Source diff could not be displayed: it is too large. Options to address this: view the blob.
...@@ -21,10 +21,11 @@ class App { ...@@ -21,10 +21,11 @@ class App {
ignore: ['/bar'], ignore: ['/bar'],
disableErrorCounter: false, disableErrorCounter: false,
disableRouteCounter: false, disableRouteCounter: false,
disableDurationCounter: false disableDurationCounter: false,
disableDefaultMetrics: false
}) })
this.router.use(this.metrics.start.bind(this.metrics)) this.router.use(this.metrics.collect)
this.router.get('/favicon.ico', (req, res) => res.status(204)) // No Favicon here this.router.get('/favicon.ico', (req, res) => res.status(204)) // No Favicon here
......
...@@ -4,3 +4,84 @@ ...@@ -4,3 +4,84 @@
- Call all Routes - Call all Routes
- Check if _metrics has a good start - Check if _metrics has a good start
*/ */
import { Metrics } from './index'
describe('metrics', () => {
beforeEach(() => {
jest.resetModules()
})
describe('constructor / options', () => {
it('should enable all 3 checks and default metrics by default', () => {
const metrics = new Metrics({})
expect(metrics._disableDurationCounter).toBeFalsy()
expect(metrics._disableErrorCounter).toBeFalsy()
expect(metrics._disableRouteCounter).toBeFalsy()
expect(metrics._disableDefaultMetrics).toBeFalsy()
})
it('should disable Route Counter if option is given', () => {
const metrics = new Metrics({
disableRouteCounter: true
})
expect(metrics._disableDurationCounter).toBeFalsy()
expect(metrics._disableErrorCounter).toBeFalsy()
expect(metrics._disableRouteCounter).toBeTruthy()
expect(metrics._disableDefaultMetrics).toBeFalsy()
})
it('should disable Error Counter if option is given', () => {
const metrics = new Metrics({
disableErrorCounter: true
})
expect(metrics._disableDurationCounter).toBeFalsy()
expect(metrics._disableErrorCounter).toBeTruthy()
expect(metrics._disableRouteCounter).toBeFalsy()
expect(metrics._disableDefaultMetrics).toBeFalsy()
})
it('should disable Duration Counter if option is given', () => {
const metrics = new Metrics({
disableDurationCounter: true
})
expect(metrics._disableDurationCounter).toBeTruthy()
expect(metrics._disableErrorCounter).toBeFalsy()
expect(metrics._disableRouteCounter).toBeFalsy()
expect(metrics._disableDefaultMetrics).toBeFalsy()
})
it('should disable Default Metrics if option is given', () => {
const metrics = new Metrics({
disableDefaultMetrics: true
})
expect(metrics._disableDurationCounter).toBeFalsy()
expect(metrics._disableErrorCounter).toBeFalsy()
expect(metrics._disableRouteCounter).toBeFalsy()
expect(metrics._disableDefaultMetrics).toBeTruthy()
})
it('should ignore /_metrics and /favicon.ico by default', () => {
const metrics = new Metrics()
expect(metrics._ignore.length).toBe(2)
expect(metrics._ignore).toContain('/_metrics')
expect(metrics._ignore).toContain('/favicon.ico')
})
it('should ignore given Routes, /_metrics and /favicon.ico by option', () => {
const metrics = new Metrics({
ignore: ['/foo', '/bar']
})
expect(metrics._ignore.length).toBe(4)
expect(metrics._ignore).toContain('/foo')
expect(metrics._ignore).toContain('/bar')
expect(metrics._ignore).toContain('/_metrics')
expect(metrics._ignore).toContain('/favicon.ico')
})
})
describe('collect()', () => {
it.todo('should measure all 3 checks by default')
it.todo('should disable Route Counter if option is given')
it.todo('should disable Error Counter if option is given')
it.todo('should disable Duration Counter if option is given')
})
describe('endpoint()', () => {
it.todo('should display all 3 basic metrics and default metrics by default')
it.todo('should not scrape default metrics if disabled')
})
})
import * as express from 'express' import * as express from 'express'
import Prometheus = require('prom-client')
export interface Options { export interface Options {
ignore: string[] ignore: string[]
disableRouteCounter: boolean disableRouteCounter: boolean
disableErrorCounter: boolean disableErrorCounter: boolean
disableDurationCounter: boolean disableDurationCounter: boolean
disableDefaultMetrics: boolean
} }
export class Metrics { export class Metrics {
private readonly _ignore: string[] public readonly _ignore: string[]
private readonly _disableRouteCounter: boolean public readonly _disableRouteCounter: boolean
private readonly _disableErrorCounter: boolean public readonly _disableErrorCounter: boolean
private readonly _disableDurationCounter: boolean public readonly _disableDurationCounter: boolean
public readonly _disableDefaultMetrics: boolean
public readonly _client: any
public readonly _collectDefaultMetrics: any
public readonly _httpRequestDurationMicroseconds: any public readonly _httpRequestDurationMicroseconds: any
public readonly _numOfRequests: any public readonly _numOfRequests: any
public readonly _numOfErrors: any public readonly _numOfErrors: any
constructor (options: Partial<Options> = {}) { constructor (options: Partial<Options> = {}) {
this._client = require('prom-client')
if (typeof options.ignore !== 'undefined') { if (typeof options.ignore !== 'undefined') {
this._ignore = options.ignore this._ignore = options.ignore
this._ignore.push('/_metrics') this._ignore.push('/_metrics')
...@@ -41,26 +47,34 @@ export class Metrics { ...@@ -41,26 +47,34 @@ export class Metrics {
} else { } else {
this._disableDurationCounter = false this._disableDurationCounter = false
} }
if (typeof options.disableDefaultMetrics !== 'undefined') {
this._disableDefaultMetrics = options.disableDefaultMetrics
} else {
this._disableDefaultMetrics = false
}
if (this._disableDefaultMetrics) {
this._collectDefaultMetrics = this._client.collectDefaultMetrics
}
this._httpRequestDurationMicroseconds = new Prometheus.Histogram({ this._httpRequestDurationMicroseconds = new this._client.Histogram({
name: 'http_request_duration_ms', name: 'http_request_duration_ms',
help: 'Duration of HTTP requests in ms', help: 'Duration of HTTP requests in ms',
labelNames: ['method', 'route', 'code'], labelNames: ['method', 'route', 'code'],
buckets: [0.10, 5, 15, 50, 100, 200, 300, 400, 500] buckets: [0.10, 5, 15, 50, 100, 200, 300, 400, 500]
}) })
this._numOfRequests = new Prometheus.Counter({ this._numOfRequests = new this._client.Counter({
name: 'numOfRequests', name: 'numOfRequests',
help: 'Number of requests made to a route', help: 'Number of requests made to a route',
labelNames: ['route'] labelNames: ['route']
}) })
this._numOfErrors = new Prometheus.Counter({ this._numOfErrors = new this._client.Counter({
name: 'numOfErrors', name: 'numOfErrors',
help: 'Number of errors', help: 'Number of errors',
labelNames: ['error'] labelNames: ['error']
}) })
} }
public start (req: express.Request, res: express.Response, next: express.NextFunction): void { public collect = (req: express.Request, res: express.Response, next: express.NextFunction): void => {
res.locals.startEpoch = Date.now() res.locals.startEpoch = Date.now()
res.on('finish', () => { res.on('finish', () => {
if (!this._ignore.includes(req.originalUrl)) { if (!this._ignore.includes(req.originalUrl)) {
...@@ -83,9 +97,12 @@ export class Metrics { ...@@ -83,9 +97,12 @@ export class Metrics {
next() next()
} }
public endpoint (req: express.Request, res: express.Response): void { public endpoint = (req: express.Request, res: express.Response): void => {
res.set('Content-Type', Prometheus.register.contentType) if (!this._disableDefaultMetrics) {
res.end(Prometheus.register.metrics()) this._collectDefaultMetrics()
}
res.set('Content-Type', this._client.register.contentType)
res.end(this._client.register.metrics())
} }
} }
export default Metrics export default Metrics
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment