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

Done

parent 45d58d0b
Branches
No related tags found
1 merge request!1Master to main
......@@ -33,6 +33,34 @@ The Following Options may be used to configure the behaviour.
- disableErrorCounter: Disable the Error Counter. Default: false
- disableRouteCounter: Disable the Route Counter. Default: false
- disableDurationCounter: Disable the Duration Counter. Default: false
- disableDefaultMetrics: Disable the Collection of default metrics. Default: false
#### Default Metrics
- process_cpu_user_seconds_total Total user CPU time spent in seconds.
- process_cpu_system_seconds_total Total system CPU time spent in seconds.
- process_cpu_seconds_total Total user and system CPU time spent in seconds.
- process_start_time_seconds Start time of the process since unix epoch in seconds.
- process_resident_memory_bytes Resident memory size in bytes.
- nodejs_eventloop_lag_seconds Lag of event loop in seconds.
- nodejs_eventloop_lag_min_seconds The minimum recorded event loop delay.
- nodejs_eventloop_lag_max_seconds The maximum recorded event loop delay.
- nodejs_eventloop_lag_mean_seconds The mean of the recorded event loop delays.
- nodejs_eventloop_lag_stddev_seconds The standard deviation of the recorded event loop delays.
- nodejs_eventloop_lag_p50_seconds The 50th percentile of the recorded event loop delays.
- nodejs_eventloop_lag_p90_seconds The 90th percentile of the recorded event loop delays.
- nodejs_eventloop_lag_p99_seconds The 99th percentile of the recorded event loop delays.
- nodejs_active_handles Number of active libuv handles grouped by handle type. Every handle type is C++ class name.
- nodejs_active_handles_total Total number of active handles.
- nodejs_active_requests Number of active libuv requests grouped by request type. Every request type is C++ class name.
- nodejs_active_requests_total Total number of active requests.
- nodejs_heap_size_total_bytes Process heap size from Node.js in bytes.
- nodejs_heap_size_used_bytes Process heap size used from Node.js in bytes.
- nodejs_external_memory_bytes Node.js external memory size in bytes.
- nodejs_heap_space_size_total_bytes Process heap space size total from Node.js in bytes.
- nodejs_heap_space_size_used_bytes Process heap space size used from Node.js in bytes.
- nodejs_heap_space_size_available_bytes Process heap space size available from Node.js in bytes.
- nodejs_version_info Node.js version info.
## Examples
......
# TODO
- disable default metrics
- tests
- mutation tests
- sonarqube disable examples and docs
- publish to npm
This diff is collapsed.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="mutation-test-elements.js"></script>
</head>
<body>
<img class="stryker-image" alt="Stryker" src="stryker-80x80.png"
style="position: fixed; right: 0; top: 0; z-index: 10">
<mutation-test-report-app titlePostfix="Stryker">
Your browser doesn't support <a href="https://caniuse.com/#search=custom%20elements">custom elements</a>.
Please use a latest version of an evergreen browser (Firefox, Chrome, Safari, Opera, etc).
</mutation-test-report-app>
<script src="bind-mutation-test-report.js"></script>
</body>
</html>
This diff is collapsed.
docs/mutation/stryker-80x80.png

6.05 KiB

This diff is collapsed.
......@@ -4848,6 +4848,136 @@
"integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==",
"dev": true
},
"mock-express-request": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/mock-express-request/-/mock-express-request-0.2.2.tgz",
"integrity": "sha512-EymHjY1k1jWIsaVaCsPdFterWO18gcNwQMb99OryhSBtIA33SZJujOLeOe03Rf2DTV997xLPyl2I098WCFm/mA==",
"dev": true,
"requires": {
"accepts": "^1.3.4",
"fresh": "^0.5.2",
"lodash": "^4.17.4",
"mock-req": "^0.2.0",
"parseurl": "^1.3.2",
"range-parser": "^1.2.0",
"type-is": "^1.6.15"
}
},
"mock-express-response": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/mock-express-response/-/mock-express-response-0.2.2.tgz",
"integrity": "sha512-+pRUv25LhyKZVSRCOzoZp8TW0nqvT7UlH7vpVzCibjjEucXL72gTgwEhmqbyTO2LI9IlyIeBBdflR9Ml5KQWMQ==",
"dev": true,
"requires": {
"content-disposition": "^0.5.2",
"content-type": "^1.0.4",
"cookie": "^0.3.1",
"cookie-signature": "^1.0.6",
"depd": "^1.1.1",
"escape-html": "^1.0.3",
"etag": "^1.8.1",
"mock-express-request": "^0.2.2",
"mock-res": "^0.5.0",
"on-finished": "^2.3.0",
"proxy-addr": "^2.0.2",
"qs": "^6.5.1",
"send": "^0.16.1",
"utils-merge": "^1.0.1",
"vary": "^1.1.2"
},
"dependencies": {
"cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
"dev": true
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"http-errors": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"dev": true,
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.0",
"statuses": ">= 1.4.0 < 2"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true
},
"mime": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==",
"dev": true
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
"send": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
"integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
"dev": true,
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "~1.6.2",
"mime": "1.4.1",
"ms": "2.0.0",
"on-finished": "~2.3.0",
"range-parser": "~1.2.0",
"statuses": "~1.4.0"
}
},
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
"dev": true
},
"statuses": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
"integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==",
"dev": true
}
}
},
"mock-req": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/mock-req/-/mock-req-0.2.0.tgz",
"integrity": "sha1-dJRGgE0sAGFpNC7nvmu6HP/VNMI=",
"dev": true
},
"mock-res": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/mock-res/-/mock-res-0.5.0.tgz",
"integrity": "sha1-mDaL6wnfdT9k9m2U5VNql7NqJDA=",
"dev": true
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
......
......@@ -46,6 +46,7 @@
"husky": "^4.2.3",
"jest": "^25.1.0",
"jest-html-reporters": "^1.2.1",
"mock-express-request": "^0.2.2",
"standard": "^14.3.3",
"supertest": "^4.0.2",
"ts-jest": "^25.2.1",
......
/*
Import.
- Start with different option packages.
- Call all Routes
- Check if _metrics has a good start
*/
import { Metrics } from './index'
const MockExpressRequest = require('mock-express-request')
const mockResponse = (statusCode?: number): any => {
const res: any = {}
res._status = 0
res.status = function (value: number) { this._status = value }
res._set = {}
res.set = function (key: string, value: any) { this._set[key] = value }
res._end = {}
res.end = function (value: any) { this._end = value }
res.locals = {}
res.on = function (event: string, fn: any) { fn() }
res.statusCode = typeof statusCode !== 'undefined' ? statusCode : 200
return res
}
describe('metrics', () => {
beforeEach(() => {
jest.resetModules()
......@@ -74,14 +84,96 @@ describe('metrics', () => {
})
})
describe('collect()', () => {
it.todo('should measure all 3 checks by default')
it('should measure all 3 checks by default', () => {
const metrics = new Metrics({})
const req = new MockExpressRequest()
req.originalUrl = '/test'
req.method = 'GET'
const res = mockResponse()
metrics.collect(req, res, () => { /**/ })
metrics.collect(req, mockResponse(400), () => { /**/ })
expect(metrics._client.register._metrics.numOfRequests.hashMap['route:/test'].value).toBe(2)
expect(metrics._client.register._metrics.numOfErrors.hashMap['error:400'].value).toBe(1)
expect(metrics._client.register._metrics.http_request_duration_ms.hashMap['code:200,method:GET,route:/test'].count).toBe(1)
})
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')
it('should disable Route Counter if option is given', () => {
const metrics = new Metrics({
disableRouteCounter: true
})
const req = new MockExpressRequest()
req.originalUrl = '/test'
req.method = 'GET'
const res = mockResponse(404)
metrics.collect(req, res, () => { /**/ })
expect(metrics._client.register._metrics.numOfErrors.hashMap['error:404'].value).toBe(1)
expect(metrics._client.register._metrics.numOfRequests).toBeUndefined()
expect(metrics._client.register._metrics.http_request_duration_ms.hashMap['code:404,method:GET,route:/test'].count).toBe(1)
})
it('should disable Error Counter if option is given', () => {
const metrics = new Metrics({
disableErrorCounter: true
})
const req = new MockExpressRequest()
req.originalUrl = '/test'
req.method = 'GET'
const res = mockResponse(404)
metrics.collect(req, res, () => { /**/ })
expect(metrics._client.register._metrics.numOfErrors).toBeUndefined()
expect(metrics._client.register._metrics.numOfRequests.hashMap['route:/test'].value).toBe(1)
expect(metrics._client.register._metrics.http_request_duration_ms.hashMap['code:404,method:GET,route:/test'].count).toBe(1)
})
it('should disable Duration Counter if option is given', () => {
const metrics = new Metrics({
disableDurationCounter: true
})
const req = new MockExpressRequest()
req.originalUrl = '/test'
req.method = 'GET'
const res = mockResponse(404)
metrics.collect(req, res, () => { /**/ })
expect(metrics._client.register._metrics.numOfErrors.hashMap['error:404'].value).toBe(1)
expect(metrics._client.register._metrics.numOfRequests.hashMap['route:/test'].value).toBe(1)
expect(metrics._client.register._metrics.http_request_duration_ms).toBeUndefined()
})
it('should ignore urls in _ignore', () => {
const metrics = new Metrics({})
const req = new MockExpressRequest()
req.originalUrl = '/_metrics'
req.method = 'GET'
const res = mockResponse()
metrics.collect(req, res, () => { /**/ })
expect(metrics._client.register._metrics.numOfRequests.hashMap).toMatchObject({})
expect(metrics._client.register._metrics.numOfErrors.hashMap).toMatchObject({})
expect(metrics._client.register._metrics.http_request_duration_ms.hashMap).toMatchObject({})
})
})
describe('endpoint()', () => {
it.todo('should display all 3 basic metrics and default metrics by default')
it.todo('should not scrape default metrics if disabled')
it('should display all 3 basic metrics and default metrics by default', () => {
const metrics = new Metrics({})
const req = new MockExpressRequest()
const res = mockResponse()
metrics.endpoint(req, res)
expect(res._status).toBe(200)
expect(res._set['Content-Type']).toBe('text/plain; version=0.0.4; charset=utf-8')
expect(res._end).toMatch(/http_request_duration_ms/)
expect(res._end).toMatch(/numOfRequests/)
expect(res._end).toMatch(/numOfErrors/)
expect(res._end).toMatch(/process_cpu_user_seconds_total/)
})
it('should not scrape default metrics if disabled', () => {
const metrics = new Metrics({
disableDefaultMetrics: true
})
const req = new MockExpressRequest()
const res = mockResponse()
metrics.endpoint(req, res)
expect(res._status).toBe(200)
expect(res._set['Content-Type']).toBe('text/plain; version=0.0.4; charset=utf-8')
expect(res._end).toMatch(/http_request_duration_ms/)
expect(res._end).toMatch(/numOfRequests/)
expect(res._end).toMatch(/numOfErrors/)
expect(res._end).not.toMatch(/process_cpu_user_seconds_total/)
})
})
})
......@@ -16,7 +16,6 @@ export class Metrics {
public readonly _disableDefaultMetrics: boolean
public readonly _client: any
public readonly _collectDefaultMetrics: any
public readonly _httpRequestDurationMicroseconds: any
public readonly _numOfRequests: any
......@@ -52,27 +51,32 @@ export class Metrics {
} else {
this._disableDefaultMetrics = false
}
if (this._disableDefaultMetrics) {
this._collectDefaultMetrics = this._client.collectDefaultMetrics
if (!this._disableDefaultMetrics) {
this._client._collectDefaultMetrics = this._client.collectDefaultMetrics
}
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._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']
})
this._numOfErrors = new this._client.Counter({
name: 'numOfErrors',
help: 'Number of errors',
labelNames: ['error']
}
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 collect = (req: express.Request, res: express.Response, next: express.NextFunction): void => {
res.locals.startEpoch = Date.now()
......@@ -99,9 +103,10 @@ export class Metrics {
public endpoint = (req: express.Request, res: express.Response): void => {
if (!this._disableDefaultMetrics) {
this._collectDefaultMetrics()
this._client._collectDefaultMetrics()
}
res.set('Content-Type', this._client.register.contentType)
res.status(200)
res.end(this._client.register.metrics())
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment