Socket
Socket
Sign inDemoInstall

swagger-stats

Package Overview
Dependencies
88
Maintainers
1
Versions
39
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.95.7 to 0.95.8

examples/hapijstest/hapijstest.js

2

examples/authtest/authtest.js

@@ -67,3 +67,3 @@ 'use strict';

name: 'swagger-stats-authtest',
version: '0.95.7',
version: '0.95.8',
hostname: "hostname",

@@ -70,0 +70,0 @@ ip: "127.0.0.1",

@@ -79,3 +79,3 @@ 'use strict';

name: 'swagger-stats-spectest',
version: '0.95.7',
version: '0.95.8',
hostname: "hostname",

@@ -82,0 +82,0 @@ ip: "127.0.0.1",

@@ -126,3 +126,3 @@ 'use strict';

apirouter.get('/redirect', function (req, res) {
res.redirect('/api/v1/success');
res.redirect('/v2/success');
});

@@ -129,0 +129,0 @@

@@ -34,3 +34,3 @@ 'use strict';

// all environments
app.set('port', process.env.PORT || 3030);
app.set('port', process.env.PORT || 3040);

@@ -113,3 +113,3 @@ // Suppress cache on the GET API responses

name: 'swagger-stats-testapp',
version: '0.95.7',
version: '0.95.8',
timelineBucketDuration: tlBucket,

@@ -130,3 +130,3 @@ uriPath: '/swagger-stats',

// Connect API Router - it should be the end of the chain
app.use('/api/v1', API);
app.use('/v2', API);

@@ -133,0 +133,0 @@ // Setup server

@@ -323,3 +323,3 @@ /**

var url = req.originalUrl;
var url = req.sws.originalUrl;

@@ -411,3 +411,3 @@ req.sws.match = false; // No match by default

case "query":
if( ('query' in req) && (pname in req.query) ){
if( ('query' in req.sws) && (pname in req.sws.query) ){
param.hits++;

@@ -450,4 +450,4 @@ }else if(isRrequired){

case "query":
if(('query' in req) && (pname in req.query)) {
paramValues[pname] = swsUtil.swsStringValue(req.query[pname]);
if(('query' in req.sws) && (pname in req.sws.query)) {
paramValues[pname] = swsUtil.swsStringValue(req.sws.query[pname]);
}

@@ -476,3 +476,3 @@ break;

var req = res.req;
var req = res._swsReq;
var codeclass = swsUtil.getStatusCodeClass(res.statusCode);

@@ -479,0 +479,0 @@

@@ -194,2 +194,5 @@ /**

this.promClientMetrics.api_all_request_in_processing_total.inc();
req.sws.inflightTimer = setTimeout(function() {
this.promClientMetrics.api_all_request_in_processing_total.dec();
}.bind(this), 250000);
};

@@ -201,3 +204,3 @@

var req = res.req;
var req = res._swsReq;

@@ -209,3 +212,3 @@ // Defaults

var timelineid = 0;
var path = req.originalUrl;
var path = req.sws.originalUrl;

@@ -233,2 +236,3 @@ // TODO move all this to Processor, so it'll be in single place

path = req['sws'].api_path;
clearTimeout(req.sws.inflightTimer);
}

@@ -235,0 +239,0 @@

@@ -38,2 +38,5 @@ /**

this.elasticUsername = null;
this.elasticPassword = null;
this.indexPrefix = "api-";

@@ -71,2 +74,10 @@

if(swsUtil.supportedOptions.elasticsearchUsername in swsOptions) {
this.elasticUsername = swsOptions[swsUtil.supportedOptions.elasticsearchUsername];
}
if(swsUtil.supportedOptions.elasticsearchPassword in swsOptions) {
this.elasticPassword = swsOptions[swsUtil.supportedOptions.elasticsearchPassword];
}
// Check / Initialize schema

@@ -88,3 +99,15 @@ this.initTemplate();

var templateURL = this.elasticURL+'/_template/template_api';
request.get({url:templateURL, json:true}, function (error, response, body) {
var getOptions = {url:templateURL, json:true};
var putOptions = {url:templateURL, json:indexTemplate};
if (this.elasticUsername && this.elasticPassword) {
var auth = {
username: this.elasticUsername,
password: this.elasticPassword,
}
getOptions.auth = auth;
putOptions.auth = auth;
}
request.get(getOptions, function (error, response, body) {
if(error) {

@@ -107,3 +130,3 @@ debug("Error querying template:", JSON.stringify(error) );

if(initializeNeeded){
request.put({url:templateURL,json:indexTemplate}, function (error, response, body) {
request.put(putOptions, function (error, response, body) {
if(error) {

@@ -193,2 +216,9 @@ debug("Failed to update template:", JSON.stringify(error));

if (this.elasticUsername && this.elasticPassword) {
options.auth = {
username: this.elasticUsername,
password: this.elasticPassword,
}
}
request.post(options, function (error, response, body) {

@@ -195,0 +225,0 @@ if (error) {

@@ -40,5 +40,5 @@ /**

if(res.statusCode==404){
this.countPathHit(res.req.originalUrl,this.top_not_found);
this.countPathHit(res._swsReq.sws.originalUrl,this.top_not_found);
}else if(res.statusCode==500){
this.countPathHit(res.req.originalUrl,this.top_server_error);
this.countPathHit(res._swsReq.sws.originalUrl,this.top_server_error);
}

@@ -45,0 +45,0 @@

@@ -7,13 +7,18 @@ /**

var fs = require('fs');
var path = require('path');
var debug = require('debug')('sws:interface');
var promClient = require("prom-client");
var basicAuth = require("basic-auth");
var Cookies = require('cookies');
const fs = require('fs');
const path = require('path');
const url = require('url');
const debug = require('debug')('sws:interface');
const promClient = require("prom-client");
const basicAuth = require("basic-auth");
const Cookies = require('cookies');
const uuidv1 = require('uuid/v1');
var swsUtil = require('./swsUtil');
var swsProcessor = require('./swsProcessor');
const swsUtil = require('./swsUtil');
const swsProcessor = require('./swsProcessor');
const send = require('send');
const qs = require('qs');
const {swsHapi,swsHapiPlugin} = require('./swsHapi');
// API data processor

@@ -23,3 +28,3 @@ var processor = null;

// swagger-stats default options
var swsOptions = {
let swsOptions = {
version:'',

@@ -38,2 +43,5 @@ swaggerSpec: null,

swsHapi.setDefaultOptions(swsOptions);
var uiMarkup = swsUtil.swsEmbeddedUIMarkup;

@@ -110,3 +118,3 @@

for(var op in swsUtil.supportedOptions){
for(let op in swsUtil.supportedOptions){
if(op in options){

@@ -181,3 +189,4 @@ swsOptions[op] = options[op];

msg = 'Invalid credentials';
res.status(403).end(msg);
res.statusCode = 403;
res.end(msg);
return resolve(false);

@@ -188,7 +197,9 @@ }

}else{
res.status(403).end(msg);
res.statusCode = 403;
res.end(msg);
return resolve(false);
}
}else{
res.status(403).end(msg);
res.statusCode = 403;
res.end(msg);
return resolve(false);

@@ -199,60 +210,2 @@ }

/*
if( !swsOptions.authentication ){
return true;
}
var cookies = new Cookies( req, res );
// Check session cookie
var sessionIdCookie = cookies.get('sws-session-id');
if( (sessionIdCookie !== undefined) && (sessionIdCookie !== null) ){
if( sessionIdCookie in sessionIDs ){
// renew it
//sessionIDs[sessionIdCookie] = Date.now();
storeSessionID(sessionIdCookie);
cookies.set('sws-session-id',sessionIdCookie,{path:swsOptions.uriPath,maxAge:swsOptions.sessionMaxAge*1000});
// Ok
req['sws-auth'] = true;
return true;
}
}
var authInfo = basicAuth(req);
var authenticated = false;
var msg = 'Authentication required';
if( (authInfo !== undefined) && (authInfo!==null) && ('name' in authInfo) && ('pass' in authInfo)){
if(typeof swsOptions.onAuthenticate === 'function'){
if( swsOptions.onAuthenticate(req, authInfo.name, authInfo.pass) ){
authenticated = true;
// Session is only for stats requests
if(req.url.startsWith(pathStats)){
// Generate session id
var sessid = uuidv1();
storeSessionID(sessid);
// Set session cookie with expiration in 15 min
cookies.set('sws-session-id',sessid,{path:swsOptions.uriPath,maxAge:swsOptions.sessionMaxAge*1000});
}
}else{
msg = 'Invalid credentials';
}
}
}
if( !authenticated ){
// Reconsidered 401 response. Make it be 403 to prevent browser Basic Auth pop-up in UI
res.status(403).end(msg);
return false;
}
req['sws-auth'] = true;
return true;
*/
}

@@ -273,3 +226,4 @@

res.status(200).end('Logged out');
res.statusCode = 200;
res.end('Logged out');
}

@@ -287,20 +241,9 @@

}
res.status(200);
res.statusCode = 200;
if(('sws-auth' in req) && req['sws-auth']){
res.setHeader('x-sws-authenticated','true');
}
res.json( processor.getStats( req.query ) );
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(processor.getStats(req.sws.query)));
});
/*
if(!processAuth(req,res)) {
return;
}
if(('sws-auth' in req) && req['sws-auth']){
res.setHeader('x-sws-authenticated','true');
}
res.status(200).json( processor.getStats( req.query ) );
*/
}

@@ -317,14 +260,6 @@

}
res.status(200).set('Content-Type', 'text/plain');
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(promClient.register.metrics());
});
/*
if(!processAuth(req,res)) {
return;
}
res.status(200).set('Content-Type', 'text/plain');
res.end(promClient.register.metrics());
*/
}

@@ -334,2 +269,5 @@

// Returns Hapi plugin
getHapiPlugin: swsHapiPlugin,
// Initialize swagger-stats and return

@@ -346,2 +284,6 @@ // middleware to perform API Data collection

res._swsReq = req;
req.sws = {};
req.sws.query = qs.parse(url.parse(req.url).query);
// Respond to requests handled by swagger-stats

@@ -357,3 +299,5 @@ // swagger-stats requests will not be counted in statistics

}else if(req.url.startsWith(pathUI) ){
res.status(200).send(uiMarkup);
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(uiMarkup);
return;

@@ -370,7 +314,4 @@ }else if(req.url.startsWith(pathDist)) {

};
res.sendFile(fileName, options, function (err) {
if (err) {
debug('unable to send file: %s',fileName);
}
});
res.setHeader('Content-Type', send.mime.lookup(path.basename(fileName)));
send(req, fileName, options).pipe(res);
return;

@@ -388,9 +329,27 @@ }

getCoreStats: function() {
return processor.getStats();
if(processor) {
return processor.getStats();
}else if(swsHapi.processor){
return swsHapi.processor.getStats();
}
},
// Allow get stats as prometheus format
getPromStats: function() {
return promClient.register.metrics();
},
// Expose promClient to allow for custom metrics by application
getPromClient: function () {
return promClient;
},
// Stop the processor so that Node.js can exit
stop: function () {
if(processor) {
return processor.stop();
}else if(swsHapi.processor){
return swsHapi.processor.stop();
}
}
};

@@ -91,5 +91,12 @@ /**

// Start tick
setInterval(this.tick, 200, this);
this.timer = setInterval(this.tick, 200, this);
};
// Stop
swsProcessor.prototype.stop = function () {
clearInterval(this.timer);
};
swsProcessor.prototype.processOptions = function (swsOptions) {

@@ -169,3 +176,3 @@

var req = res.req;
var req = res._swsReq;

@@ -175,5 +182,5 @@ var codeclass = swsUtil.getStatusCodeClass(res.statusCode);

var rrr = {
'path': req.originalUrl,
'path': req.sws.originalUrl,
'method': req.method,
'query' : req.method + ' ' + req.originalUrl,
'query' : req.method + ' ' + req.sws.originalUrl,
'startts': 0,

@@ -254,3 +261,3 @@ 'endts': 0,

// Express parameters: req.param and req.query
// Express/Koa parameters: req.params (router) and req.body (body parser)
if (req.hasOwnProperty("params")) {

@@ -261,5 +268,5 @@ rrr.http.request.params = {};

if (req.hasOwnProperty("query")) {
if (req.sws && req.sws.hasOwnProperty("query")) {
rrr.http.request.query = {};
swsUtil.swsStringRecursive(rrr.http.request.query, req.query);
swsUtil.swsStringRecursive(rrr.http.request.query, req.sws.query);
}

@@ -295,3 +302,3 @@

var remoteaddress = null;
var xfwd = req.header('x-forwarded-for');
var xfwd = req.headers['x-forwarded-for'];
if (xfwd) {

@@ -310,3 +317,3 @@ var fwdaddrs = xfwd.split(','); // Could be "client IP, proxy 1 IP, proxy 2 IP"

// Placeholder for sws-specific attributes
req.sws = {};
req.sws = req.sws || {};

@@ -321,2 +328,3 @@ // Setup sws props and pass to stats processors

req.sws.originalUrl = req.originalUrl || req.url;
req.sws.track = true;

@@ -351,3 +359,3 @@ req.sws.startts = ts;

var req = res.req;
var req = res._swsReq;

@@ -363,5 +371,5 @@ // Capture route path for the request, if set by router

// If request was not matched to Swagger API, set API path:
// Use route_path, if exist; if not, use originalUrl
// Use route_path, if exist; if not, use sws.originalUrl
if(!('api_path' in req.sws)){
req.sws.api_path = (route_path!=''?route_path:req.originalUrl);
req.sws.api_path = (route_path!=''?route_path:req.sws.originalUrl);
}

@@ -368,0 +376,0 @@

@@ -161,3 +161,3 @@ /**

var req = res.req;
var req = res._swsReq;

@@ -164,0 +164,0 @@ // Update timeline stats

@@ -97,2 +97,8 @@ /*

// Username for Elasticsearch, if anonymous user is disbaled . Default is empty (disabled)
elasticsearchUsername : "elasticsearchUsername",
// Password for Elasticsearch, if anonymous user is disbaled . Default is empty (disabled)
elasticsearchPassword : "elasticsearchPassword",
// Set to true to track only requests defined in swagger spec. Default false.

@@ -99,0 +105,0 @@ swaggerOnly : "swaggerOnly"

{
"name": "swagger-stats",
"version": "0.95.7",
"version": "0.95.8",
"description": "API Telemetry and APM. 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,8 @@ "main": "lib/index.js",

"testonly": "mocha -S --delay",
"hapitestapp": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/hapitestapp node examples/hapijstest/hapijstest.js",
"hapitestappstop": "mocha --delay --exit test/stoptestapp.js",
"test-old": "npm run coverage && npm run karma-ci",
"coverage": "nyc --reporter=lcov --reporter=html --reporter=text --report-dir=coverage/mocha mocha -S --delay",
"test": "npm run cov000 && npm run cov010 && npm run cov100 && npm run cov200 && npm run cov300 && npm run cov400 && npm run cov500 && npm run karma-ci && npm run coverage-report",
"test": "npm run testExpress && npm run testHapi && npm run coverage-report",
"testExpress": "npm run cov000 && npm run cov010 && npm run cov100 && npm run cov200 && npm run cov300 && npm run cov400 && npm run cov500 && npm run karma-ci",
"cov000": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/000 mocha --delay --exit test/000_baseline.js",

@@ -20,2 +23,10 @@ "cov010": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/010 mocha --delay --exit test/010_swsapistats.js",

"cov500": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/500 mocha --delay --exit test/500_elastic.js",
"testHapi": "concurrently -k --success first \"npm run hapitestapp\" \"npm run covHapi\"",
"covHapi": "npm run cov000h && npm run cov100h && npm run cov200h && npm run cov300h && npm run cov500h && npm run hapitestappstop",
"cov000h": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/000h mocha --delay --exit test/000_baseline.js",
"cov100h": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/100h mocha --delay --exit test/100_method.js",
"cov200h": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/200h mocha --delay --exit test/200_apicore.js",
"cov300h": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/300h mocha --delay --exit test/300_timeline.js",
"cov400h": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/400h mocha --delay --exit test/400_auth.js",
"cov500h": "nyc --reporter=lcov --reporter=html --reporter=json --reporter=text --report-dir=coverage/500h mocha --delay --exit test/500_elastic.js",
"coverage-report": "node_modules/.bin/istanbul report --root ./coverage --dir ./coverage-report lcov",

@@ -57,3 +68,5 @@ "specstest": "mocha test/specstest/swaggerspecstest.js",

"prom-client": "^11.0.0",
"qs": "^6.7.0",
"request": "^2.85.0",
"send": "^0.17.1",
"uuid": "^3.1.0"

@@ -117,4 +130,7 @@ },

"swagger-jsdoc": "^1.9.1",
"swagger-parser": "^3.4.1"
"swagger-parser": "^3.4.1",
"@hapi/hapi": "^18.3.2",
"@hapi/inert": "^5.2.1",
"concurrently": "^4.1.2"
}
}

@@ -18,6 +18,8 @@ <p align="center">

## API Telemetry and APM
## API Telemetry and APM
> Trace API calls and Monitor API performance, health and usage statistics in Node.js Microservices
### Supports Express, Koa and Hapi
**swagger-stats** traces REST API requests and responses in Node.js Microservices, and collects statistics per API Operation.

@@ -27,3 +29,2 @@ **swagger-stats** detects API operations based on express routes. You may also provide [Swagger (Open API) specification](https://swagger.io/specification/),

**swagger-stats** exposes statistics and metrics per API Operation, such as `GET /myapi/:parameter`, or `GET /pet/{petId}`

@@ -98,2 +99,4 @@

#### Express
```javascript

@@ -105,4 +108,40 @@ var swStats = require('swagger-stats');

See `/examples` for sample apps
#### Koa
[`express-to-koa`](https://github.com/kaelzhang/express-to-koa) can be used which is just a simple `Promise` wrapper.
```javascript
var swStats = require('swagger-stats');
var apiSpec = require('swagger.json');
var e2k = require('express-to-koa');
app.use(e2k(swStats.getMiddleware({ swaggerSpec:apiSpec })));
```
#### Hapi
```javascript
const swStats = require('swagger-stats');
const swaggerSpec = require('./petstore.json');
const init = async () => {
server = Hapi.server({
port: 3040,
host: 'localhost'
});
await server.register({
plugin: swStats.getHapiPlugin,
options: {
swaggerSpec:swaggerSpec
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
````
See `/examples` for sample apps
### Get Statistics with API

@@ -207,2 +246,8 @@

#### v0.95.8
* [feature] Hapijs support [#75](https://github.com/slanatech/swagger-stats/issues/75) - [Example how to use](https://github.com/slanatech/swagger-stats/blob/master/examples/hapijstest/hapijstest.js)
* [feature] Koa support [#70](https://github.com/slanatech/swagger-stats/pull/70), [#67](https://github.com/slanatech/swagger-stats/issues/67) - thank you @gombosg!
#### v0.95.7

@@ -209,0 +254,0 @@

Sorry, the diff of this file is not supported yet

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc