swagger-stats
Advanced tools
Comparing version 0.91.0 to 0.92.0
@@ -7,2 +7,8 @@ 'use strict'; | ||
// Prometheus Client | ||
const promClient = require('prom-client'); | ||
const collectDefaultMetrics = promClient.collectDefaultMetrics; | ||
// Probe every 1 second | ||
collectDefaultMetrics({ timeout: 1000 }); | ||
// Server | ||
@@ -42,2 +48,9 @@ var server = null; | ||
// Return Prometheus metrics from prom-client | ||
app.get('/metrics', function(req,res) { | ||
res.status(200).set('Content-Type', 'text/plain'); | ||
res.end(promClient.register.metrics()); | ||
}); | ||
// Testing validation of 3rd-party API spec | ||
@@ -51,4 +64,2 @@ var swaggerSpec = null; | ||
specLocation = process.env.SWS_SPECTEST_URL; | ||
}else{ | ||
debug('Use SWS_SPECTEST_URL environment variable to specify swagger spec'); | ||
} | ||
@@ -69,16 +80,14 @@ | ||
//app.use(swStats.getMiddleware()); | ||
// Track statistics on API request / responses | ||
// Enable swagger-stats middleware with all options | ||
app.use(swStats.getMiddleware({ | ||
name: 'swagger-stats-testapp', | ||
version: '0.90.3', | ||
name: 'swagger-stats-spectest', | ||
version: '0.92.0', | ||
hostname: "hostname", | ||
ip: "127.0.0.1", | ||
timelineBucketDuration: tlBucket, | ||
swaggerSpec:swaggerSpec | ||
// Override duration buckets | ||
//durationBuckets: [100, 1000, 5000, 20000], | ||
//requestSizeBuckets: [500, 5000, 15000, 50000], | ||
//responseSizeBuckets: [600, 6000, 6000, 60000] | ||
swaggerSpec:swaggerSpec, | ||
uriPath: '/swagger-stats', | ||
durationBuckets: [5, 10, 25], | ||
requestSizeBuckets: [5, 10, 25], | ||
responseSizeBuckets: [5, 10, 25] | ||
})); | ||
@@ -85,0 +94,0 @@ |
@@ -112,6 +112,10 @@ 'use strict'; | ||
name: 'swagger-stats-testapp', | ||
version: '0.90.3', | ||
version: '0.92.0', | ||
timelineBucketDuration: tlBucket, | ||
uriPath: '/swagger-stats', | ||
swaggerSpec:swaggerSpec | ||
swaggerSpec:swaggerSpec, | ||
promClient: false, | ||
onResponseFinish: function(req,res,rrr){ | ||
debug('onResponseFinish: %s', JSON.stringify(rrr)); | ||
} | ||
})); | ||
@@ -118,0 +122,0 @@ |
@@ -72,3 +72,4 @@ 'use strict'; | ||
{ type: 'lcov' }, | ||
{ type: 'text' } | ||
{ type: 'text' }, | ||
{ type: 'json' } | ||
] | ||
@@ -75,0 +76,0 @@ }, |
@@ -12,2 +12,5 @@ /** | ||
// Prometheus Client library will be required, if exists in the application | ||
var promClient = null; | ||
var swsUtil = require('./swsUtil'); | ||
@@ -48,2 +51,5 @@ var swsReqResStats = require('./swsReqResStats'); | ||
// prom-client metrics | ||
this.promClientMetrics = null; | ||
} | ||
@@ -246,3 +252,41 @@ | ||
if(swsOptions.promClientAvailable) { | ||
try { | ||
promClient = require("prom-client"); | ||
// Create metrics | ||
this.promClientMetrics = {}; | ||
this.promClientMetrics.api_request_total = new promClient.Counter({ | ||
name: swsUtil.swsMetrics.api_request_total.name, | ||
help: swsUtil.swsMetrics.api_request_total.help, | ||
labelNames: ['method','path','code'] }); | ||
this.promClientMetrics.api_request_duration_milliseconds = new promClient.Histogram({ | ||
name: swsUtil.swsMetrics.api_request_duration_milliseconds.name, | ||
help: swsUtil.swsMetrics.api_request_duration_milliseconds.help, | ||
labelNames: ['method','path'], | ||
buckets: this.durationBuckets }); | ||
this.promClientMetrics.api_request_size_bytes = new promClient.Histogram({ | ||
name: swsUtil.swsMetrics.api_request_size_bytes.name, | ||
help: swsUtil.swsMetrics.api_request_size_bytes.help, | ||
labelNames: ['method','path'], | ||
buckets: this.requestSizeBuckets }); | ||
this.promClientMetrics.api_response_size_bytes = new promClient.Histogram({ | ||
name: swsUtil.swsMetrics.api_response_size_bytes.name, | ||
help: swsUtil.swsMetrics.api_response_size_bytes.help, | ||
labelNames: ['method','path'], | ||
buckets: this.responseSizeBuckets }); | ||
this.usePromClient = true; | ||
} catch (e) {} | ||
} | ||
if(!('swaggerSpec' in swsOptions)) return; | ||
@@ -607,4 +651,13 @@ if(swsOptions.swaggerSpec === null) return; | ||
// prm-client metrics update | ||
// Add prom-client metrics, if prom-client is available | ||
if(this.promClientMetrics !== null){ | ||
this.promClientMetrics.api_request_total.labels(req.method,req.sws.api_path,res.statusCode).inc(); | ||
this.promClientMetrics.api_request_duration_milliseconds.labels(req.method,req.sws.api_path).observe(req.sws.duration); | ||
this.promClientMetrics.api_request_size_bytes.labels(req.method,req.sws.api_path).observe(req.sws.req_clength); | ||
this.promClientMetrics.api_response_size_bytes.labels(req.method,req.sws.api_path).observe(req.sws.res_clength); | ||
} | ||
}; | ||
module.exports = swsAPIStats; |
@@ -11,2 +11,5 @@ /** | ||
// Prometheus Client library will be required, if exists in the application | ||
var promClient = null; | ||
var swsUtil = require('./swsUtil'); | ||
@@ -55,2 +58,6 @@ var swsReqResStats = require('./swsReqResStats'); | ||
]; | ||
// prom-client metrics | ||
this.promClientMetrics = null; | ||
} | ||
@@ -60,2 +67,50 @@ | ||
swsCoreStats.prototype.initialize = function (swsOptions) { | ||
if(swsOptions.promClientAvailable){ | ||
// Will use prom-client | ||
promClient = require("prom-client"); | ||
// Create metrics | ||
this.promClientMetrics = {}; | ||
// Register all provided metrics in prom-client | ||
this.promClientMetrics.api_all_request_total = new promClient.Counter({ | ||
name: swsUtil.swsMetrics.api_all_request_total.name, | ||
help: swsUtil.swsMetrics.api_all_request_total.help }); | ||
this.promClientMetrics.api_all_success_total = new promClient.Counter({ | ||
name: swsUtil.swsMetrics.api_all_success_total.name, | ||
help: swsUtil.swsMetrics.api_all_success_total.help }); | ||
this.promClientMetrics.api_all_errors_total = new promClient.Counter({ | ||
name: swsUtil.swsMetrics.api_all_errors_total.name, | ||
help: swsUtil.swsMetrics.api_all_errors_total.help }); | ||
this.promClientMetrics.api_all_client_error_total = new promClient.Counter({ | ||
name: swsUtil.swsMetrics.api_all_client_error_total.name, | ||
help: swsUtil.swsMetrics.api_all_client_error_total.help }); | ||
this.promClientMetrics.api_all_server_error_total = new promClient.Counter({ | ||
name: swsUtil.swsMetrics.api_all_server_error_total.name, | ||
help: swsUtil.swsMetrics.api_all_server_error_total.help }); | ||
this.promClientMetrics.api_all_request_in_processing_total = new promClient.Gauge({ | ||
name: swsUtil.swsMetrics.api_all_request_in_processing_total.name, | ||
help: swsUtil.swsMetrics.api_all_request_in_processing_total.help }); | ||
this.promClientMetrics.nodejs_process_memory_rss_bytes = new promClient.Gauge({ | ||
name: swsUtil.swsMetrics.nodejs_process_memory_rss_bytes.name, | ||
help: swsUtil.swsMetrics.nodejs_process_memory_rss_bytes.help }); | ||
this.promClientMetrics.nodejs_process_memory_heap_total_bytes = new promClient.Gauge({ | ||
name: swsUtil.swsMetrics.nodejs_process_memory_heap_total_bytes.name, | ||
help: swsUtil.swsMetrics.nodejs_process_memory_heap_total_bytes.help }); | ||
this.promClientMetrics.nodejs_process_memory_heap_used_bytes = new promClient.Gauge({ | ||
name: swsUtil.swsMetrics.nodejs_process_memory_heap_used_bytes.name, | ||
help: swsUtil.swsMetrics.nodejs_process_memory_heap_used_bytes.help }); | ||
this.promClientMetrics.nodejs_process_memory_external_bytes = new promClient.Gauge({ | ||
name: swsUtil.swsMetrics.nodejs_process_memory_external_bytes.name, | ||
help: swsUtil.swsMetrics.nodejs_process_memory_external_bytes.help }); | ||
this.promClientMetrics.nodejs_process_cpu_usage_percentage = new promClient.Gauge({ | ||
name: swsUtil.swsMetrics.nodejs_process_cpu_usage_percentage.name, | ||
help: swsUtil.swsMetrics.nodejs_process_cpu_usage_percentage.help }); | ||
} | ||
}; | ||
@@ -124,2 +179,11 @@ | ||
this.sys.cpu = cpuPercent; | ||
// Update prom-client metrics | ||
if(this.promClientMetrics !== null) { | ||
this.promClientMetrics.nodejs_process_memory_rss_bytes.set(this.sys.rss); | ||
this.promClientMetrics.nodejs_process_memory_heap_total_bytes.set(this.sys.heapTotal); | ||
this.promClientMetrics.nodejs_process_memory_heap_used_bytes.set(this.sys.heapUsed); | ||
this.promClientMetrics.nodejs_process_memory_external_bytes.set(this.sys.external); | ||
this.promClientMetrics.nodejs_process_cpu_usage_percentage.set(this.sys.cpu); | ||
} | ||
}; | ||
@@ -139,2 +203,8 @@ | ||
this.method[method].countRequest(req.sws.req_clength); | ||
// Update prom-client metrics | ||
if(this.promClientMetrics !== null){ | ||
this.promClientMetrics.api_all_request_total.inc(); | ||
this.promClientMetrics.api_all_request_in_processing_total.inc(); | ||
} | ||
}; | ||
@@ -189,4 +259,24 @@ | ||
} | ||
// Update prom-client metrics | ||
if(this.promClientMetrics !== null){ | ||
switch(codeclass){ | ||
case "success": | ||
this.promClientMetrics.api_all_success_total.inc(); | ||
break; | ||
case "redirect": | ||
this.promClientMetrics.api_all_errors_total.inc(); | ||
break; | ||
case "client_error": | ||
this.promClientMetrics.api_all_client_error_total.inc(); | ||
break; | ||
case "server_error": | ||
this.promClientMetrics.api_all_server_error_total.inc(); | ||
break; | ||
} | ||
this.promClientMetrics.api_all_request_in_processing_total.dec(); | ||
} | ||
}; | ||
module.exports = swsCoreStats; |
@@ -13,2 +13,5 @@ /** | ||
// Prometheus Client library will be required, if exists in the application | ||
var promClient = null; | ||
var swsUtil = require('./swsUtil'); | ||
@@ -27,3 +30,7 @@ var swsProcessor = require('./swsProcessor'); | ||
requestSizeBuckets: [5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000], | ||
responseSizeBuckets: [5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000] | ||
responseSizeBuckets: [5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000], | ||
promClient: true, | ||
onResponseFinish: null, | ||
// internal option: Will be set to true if prom-client module is available in the application | ||
promClientAvailable: false | ||
}; | ||
@@ -37,2 +44,3 @@ | ||
var pathMetrics = swsOptions.uriPath+'/metrics'; | ||
var pathMetricsInt = swsOptions.uriPath+'/metrics-int'; | ||
@@ -73,2 +81,14 @@ // Request hanlder | ||
// Check for prom-client | ||
if( swsOptions.promClient ) { | ||
try { | ||
var a = require.resolve("prom-client"); | ||
swsOptions.promClientAvailable = true; | ||
promClient = require("prom-client"); | ||
} catch (e) { | ||
debug("prom-client module is not found, using embedded metrics"); | ||
swsOptions.promClientAvailable = true; | ||
} | ||
} | ||
// update standard path | ||
@@ -79,2 +99,3 @@ pathUI = swsOptions.uriPath+'/ui'; | ||
pathMetrics = swsOptions.uriPath+'/metrics'; | ||
pathMetricsInt = swsOptions.uriPath+'/metrics-int'; | ||
} | ||
@@ -94,10 +115,12 @@ | ||
//res.status(200) | ||
// .set('Content-Type', 'text/plain') | ||
// .send( processor.getMetrics( req.query ) ); | ||
res.status(200).set('Content-Type', 'text/plain'); | ||
var usePromClient = ((promClient !== null) && !(req.url.startsWith(pathMetricsInt))); | ||
processor.writeMetrics(req.query, res); | ||
res.end(); | ||
if( usePromClient ){ | ||
res.status(200).set('Content-Type', 'text/plain'); | ||
res.end(promClient.register.metrics()); | ||
}else { | ||
res.status(200).set('Content-Type', 'text/plain'); | ||
processor.writeMetrics(req.query, res); | ||
res.end(); | ||
} | ||
} | ||
@@ -104,0 +127,0 @@ |
@@ -19,3 +19,3 @@ /** | ||
// Lowest duration from all stored requests | ||
this.lowest = -1; | ||
this.lowest = -1; // will be updated by first request | ||
@@ -59,3 +59,3 @@ // Max number of requests to keep. | ||
for(var i=0;(i<this.longest_requests.length) && (idx==-1);i++){ | ||
if( duration < this.longest_requests[i].duration ){ | ||
if( duration < this.longest_requests[i].responsetime ){ | ||
idx = i; | ||
@@ -89,3 +89,3 @@ } | ||
// First entry duration is now the smallest one | ||
this.lowest = this.longest_requests[0].duration; | ||
this.lowest = this.longest_requests[0].responsetime; | ||
@@ -92,0 +92,0 @@ this.placeReqResData(rrr); |
@@ -45,2 +45,4 @@ /** | ||
// onResponseFinish callback, if specified in options | ||
this.onResponseFinish = null; | ||
@@ -124,2 +126,6 @@ // Core statistics | ||
if( swsOptions.onResponseFinish && (typeof swsOptions.onResponseFinish === 'function') ){ | ||
this.onResponseFinish = swsOptions.onResponseFinish; | ||
} | ||
}; | ||
@@ -348,5 +354,10 @@ | ||
// Pass to app if callback is specified | ||
if(this.onResponseFinish !== null ){ | ||
this.onResponseFinish(req,res,rrr); | ||
} | ||
// TODO Push Request/Response Data to Emitter(s) | ||
debugrrr('%s', JSON.stringify(rrr)); | ||
//debugrrr('%s', JSON.stringify(rrr)); | ||
}; | ||
@@ -408,10 +419,2 @@ | ||
// Return all available metrics for Prometheus | ||
swsProcessor.prototype.getMetrics = function ( query ) { | ||
var metrics = ''; | ||
metrics += this.coreStats.getMetrics(); | ||
//metrics += this.apiStats.getMetrics(); | ||
return metrics; | ||
}; | ||
// Write prometheus metrics to stream | ||
@@ -418,0 +421,0 @@ swsProcessor.prototype.writeMetrics = function ( query, stream ) { |
@@ -41,3 +41,3 @@ /* | ||
// The default buckets are tailored to broadly measure API response time. | ||
// Most likely needs to be defined per to account for application specifics. | ||
// Most likely needs to be defined per app to account for application specifics. | ||
durationBuckets : "durationBuckets", | ||
@@ -49,11 +49,27 @@ | ||
// The default buckets are tailored to broadly measure API request size. | ||
// Most likely needs to be defined per to account for application specifics. | ||
// Most likely needs to be defined per app to account for application specifics. | ||
requestSizeBuckets : "requestSizeBuckets", | ||
// Buckets for request size histogram metric, in Bytes | ||
// Buckets for response size histogram metric, in Bytes | ||
// Optional. Default value: | ||
// [5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000] | ||
// The default buckets are tailored to broadly measure API request size. | ||
// Most likely needs to be defined per to account for application specifics. | ||
responseSizeBuckets : "responseSizeBuckets" | ||
// The default buckets are tailored to broadly measure API response size. | ||
// Most likely needs to be defined per app to account for application specifics. | ||
responseSizeBuckets : "responseSizeBuckets", | ||
// Whether to use prom-client Prometheus client library from the application | ||
// If set to true (default), swagger-stats will attempt to detect if prom-client module is available | ||
// in the application, and if yes, use it | ||
// If set to false, prom-client will not be used | ||
promClient : "promClient", | ||
// Callback to invoke when response is finished - https://github.com/slanatech/swagger-stats/issues/5 | ||
// Application may implement it to trace Request Response Record (RRR), which is passed as parameter | ||
// the following parameters are passed to this callback: | ||
// OnResponseFinish(req,res,rrr) | ||
// - req - request | ||
// - res - response | ||
// - rrr - Request Response Record (RRR) | ||
onResponseFinish : "onResponseFinish" | ||
}; | ||
@@ -60,0 +76,0 @@ |
{ | ||
"name": "swagger-stats", | ||
"version": "0.91.0", | ||
"version": "0.92.0", | ||
"description": "Telemetry for your APIs. Trace API calls and Monitor API performance, health and usage statistics in Node.js Microservices, based on express routes and Swagger (Open API) specification", | ||
@@ -9,5 +9,10 @@ "main": "lib/index.js", | ||
"testonly": "mocha -S --delay", | ||
"test": "npm run coverage && npm run karma-ci", | ||
"test-old": "npm run coverage && npm run karma-ci", | ||
"coverage": "nyc --reporter=lcov --reporter=html --reporter=text --report-dir=coverage/mocha mocha -S --delay", | ||
"coverage-report": "nyc report", | ||
"test": "npm run cov000 && npm run cov100 && npm run cov200 && npm run cov300 && npm run karma-ci && npm run coverage-report", | ||
"cov000": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/000 mocha --delay test/000_baseline.js", | ||
"cov100": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/100 mocha --delay test/100_method.js", | ||
"cov200": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/200 mocha --delay test/200_apicore.js", | ||
"cov300": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/300 mocha --delay test/300_timeline.js", | ||
"coverage-report": "node_modules/.bin/istanbul report --root ./coverage --dir ./coverage-report lcov", | ||
"specstest": "mocha test/specstest/swaggerspecstest.js", | ||
@@ -93,2 +98,3 @@ "karma": "NODE_ENV=test karma start karma.conf.js", | ||
"postcss-loader": "^2.0.5", | ||
"prom-client": "^10.1.1", | ||
"q": "^1.5.0", | ||
@@ -95,0 +101,0 @@ "serve-favicon": "^2.4.5", |
@@ -186,2 +186,9 @@ <p align="center"> | ||
#### v0.92.0 | ||
* [feature] Support providing Prometheus metrics via [prom-client](https://www.npmjs.com/package/prom-client) library [#20](https://github.com/slanatech/swagger-stats/issues/20) | ||
* [feature] OnResponseFinish hook: pass request/response record to callback so app can post proceses it add it to the log [#5](https://github.com/slanatech/swagger-stats/issues/5) | ||
#### v0.91.0 | ||
@@ -188,0 +195,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
8785008
76
7557
232
56