UNPKG

swagger-stats

Version:

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

195 lines (153 loc) 5.82 kB
'use strict'; var http = require('http'); var path = require('path'); var debug = require('debug')('sws:spectest'); //http.globalAgent.keepAlive = true; // Prometheus Client const promClient = require('prom-client'); const collectDefaultMetrics = promClient.collectDefaultMetrics; // Probe every 1 second collectDefaultMetrics({ timeout: 1000 }); // Server var server = null; // Express and middlewares var express = require('express'); var expressBodyParser = require('body-parser'); var swaggerParser = require('swagger-parser'); var swStats = require('../../lib'); // require('swagger-stats'); var app = module.exports = express(); app.use(expressBodyParser.json()); app.use(expressBodyParser.urlencoded({ extended: true })); // JSON formatting app.set('json spaces', 2); app.set('json replacer', null); // all environments app.set('port', process.env.PORT || 3040); // Suppress cache on the GET API responses app.disable('etag'); app.get('/', function(req,res) { res.redirect('/swagger-stats/'); }); // Return Prometheus metrics from prom-client app.get('/metrics', function(req,res) { res.status(200).set('Content-Type', 'text/plain'); Promise.resolve(promClient.register.metrics()).then( (x) => { res.end(x); }); }); // Testing validation of 3rd-party API spec var swaggerSpec = null; var parser = new swaggerParser(); //var specLocation = 'petstore3.yaml'; var specLocation = 'petstore.yaml'; if( process.env.SWS_SPECTEST_URL ){ specLocation = process.env.SWS_SPECTEST_URL; } var tlBucket = 60000; if( process.env.SWS_SPECTEST_TIMEBUCKET ){ tlBucket = parseInt(process.env.SWS_SPECTEST_TIMEBUCKET); } debug('Loading Swagger Spec from ' + specLocation ); parser.validate(specLocation,function(err, api) { if (!err) { debug('Success validating swagger file!'); swaggerSpec = api; var swsOptions = { name: 'swagger-stats-spectest', version: '0.99.7', hostname: "hostname", ip: "127.0.0.1", timelineBucketDuration: tlBucket, swaggerSpec:swaggerSpec, //basePath: '/api', uriPath: '/swagger-stats', durationBuckets: [10, 25, 50, 100, 200], requestSizeBuckets: [10, 25, 50, 100, 200], responseSizeBuckets: [10, 25, 50, 100, 200], apdexThreshold: 25, onResponseFinish: function(req,res,rrr){ // You can remove non-needed or private attributes from Request Response Record delete rrr.http.request.headers['user-agent']; // You can also extend Request Response Record with custom attributes // All custom properties under attrs will be casted to string and indexed in ElasticSearch as keyword rrr.attrs = { test1: "test1", test2: "test2", test3: 10, test4: true, test5: {prop:"value"} }; // All custom properties under attrsint will be casted to numeric and indexed in ElasticSearch as long rrr.attrsint = { numvalue1: 100, numvalue2: "100", numvalue3: false, numvalue4: "", numvalue5: {prop:"value"} }; debug('onResponseFinish: %s', JSON.stringify(rrr)); } }; // Enable Elasticsearch if specified if( process.env.SWS_ELASTIC ){ swsOptions.elasticsearch = process.env.SWS_ELASTIC; } if( process.env.SWS_ELASTIC_INDEX_PREFIX ){ swsOptions.elasticsearchIndexPrefix = process.env.SWS_ELASTIC_INDEX_PREFIX; } // Enable swagger-stats middleware with options app.use(swStats.getMiddleware(swsOptions)); // Implement mock API app.use(mockApiImplementation); // Setup server server = http.createServer(app); server.listen(app.get('port')); server.keepAliveTimeout = 61 * 1000; server.headersTimeout = 65 * 1000; debug('Server started on port ' + app.get('port') + ' http://localhost:'+app.get('port')); } }); // Mock implementation of any API request // Supports the following parameters in x-sws-res header: // x-sws-res={ code:<response code>, // message:<message to provide in response>, // delay:<delay to respond>, // payloadsize:<size of payload JSON to generate> // } function mockApiImplementation(req,res,next){ var code = 500; var message = "MOCK API RESPONSE"; var delay = 0; var payloadsize = 0; // get header var hdrSwsRes = req.header('x-sws-res'); if(typeof hdrSwsRes !== 'undefined'){ var swsRes = JSON.parse(hdrSwsRes); if( 'code' in swsRes ) code = swsRes.code; if( 'message' in swsRes ) message = swsRes.message; if( 'delay' in swsRes ) delay = swsRes.delay; if( 'payloadsize' in swsRes ) payloadsize = swsRes.payloadsize; } if( delay > 0 ){ setTimeout(function(){ mockApiSendResponse(res,code,message,payloadsize); },delay); }else{ mockApiSendResponse(res,code,message,payloadsize); } } function mockApiSendResponse(res,code,message,payloadsize){ if(payloadsize<=0){ res.status(code).send(message); }else{ // generate dummy payload of approximate size var dummyPayload = []; var adjSize = payloadsize-4; if(adjSize<=0) adjSize = 1; var str = ''; for(var i=0;i<adjSize;i++) str += 'a'; dummyPayload.push(str); res.status(code).json(dummyPayload); } } module.exports.app = app;