Skip to content
This repository has been archived by the owner on Mar 9, 2022. It is now read-only.

Add response time and endpoint counters as metrics for Mira #236

Merged
merged 4 commits into from
Feb 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const defaultEngineMetricsPort = 9090;
const defaultEngineDiscoveryInterval = 10000;
const defaultEngineUpdateInterval = 10000;
const defaultKubernetesProxyPort = 8001;
const defaultAllowedResponseTime = 1000;
const defaultDiscoveryLabel = 'qix-engine';
const defaultEngineAPIPortLabel = 'qix-engine-api-port';
const defaultEngineMetricsPortLabel = 'qix-engine-metrics-port';
Expand Down Expand Up @@ -149,6 +150,17 @@ class Config {
Config.rollbarLevels = (process.env.MIRA_ROLLBAR_LEVELS || 'error').split(',');
logger.info(`Mira will report '${Config.rollbarLevels}' log levels to Rollbar`);
}

/**
* @prop {number} allowedResponseTime - The maximum allowed time in milliseconds from when a request is received by Mira
* until a response is being sent.
* @static
*/
Config.allowedResponseTime = parseInt(process.env.MIRA_ALLOWED_RESPONSE_TIME, 10);
if (!Config.allowedResponseTime || isNaN(Config.allowedResponseTime)) {
Config.allowedResponseTime = defaultAllowedResponseTime;
}
logger.info(`Maximum allowed response time for Mira is: ${Config.allowedResponseTime} ms`);
}
}

Expand Down
45 changes: 45 additions & 0 deletions src/Metrics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const prom = require('prom-client');
const Config = require('./Config');
const logger = require('./logger/Logger').get();
const version = require('../version');
const os = require('os');

// Create metric gauge containing build info from version.json
new prom.Gauge({
name: `${version.name}_build_info`,
help: `A metric with a constant 1 value labeled by version, revision, platform, nodeVersion, os from which ${version.name} was built`,
labelNames: ['version', 'revision', 'buildTime', 'platform', 'nodeVersion', 'os', 'osRelease'],
}).set({
version: version.version,
revision: version.SHA,
buildTime: version.buildTime,
platform: process.release.name,
nodeVersion: process.version,
os: process.platform,
osRelease: os.release(),
}, 1);

// Collect default prometheus metrics every 10 seconds
const collectDefaultMetrics = prom.collectDefaultMetrics;
collectDefaultMetrics();

// Create metric summary for api response times
const responseTimeSummary = new prom.Summary({
name: `${version.name}_api_response_time_ms`,
help: `Time in milliseconds consumed from ${version.name} receiving a request until a response is sent`,
});

// function for recording time consumed for a request and adding as metric
function recordResponseTimes() {
return async function responseTime(ctx, next) {
const requestTime = Date.now();
await next();
const diff = Math.ceil(Date.now() - requestTime);
responseTimeSummary.observe(diff);
if (diff > Config.allowedResponseTime) {
logger.warn(`Request for endpoint ${ctx.request.url} took ${diff} ms, which is longer than allowed ${Config.allowedResponseTime} ms`);
}
};
}

module.exports = recordResponseTimes;
30 changes: 9 additions & 21 deletions src/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ const Config = require('./Config');
const Router = require('koa-router');
const prom = require('prom-client');
const logger = require('./logger/Logger').get();
const version = require('../version');
const os = require('os');


const apiVersion = 'v1';
const router = new Router({
Expand All @@ -18,29 +17,15 @@ const engineDiscovery = new EngineDiscovery(
Config.engineDiscoveryInterval,
Config.engineUpdateInterval);

// Create metric gauge containing build info from version.json
new prom.Gauge({
name: `${version.name}_build_info`,
help: `A metric with a constant 1 value labeled by version, revision, platform, nodeVersion, os from which ${version.name} was built`,
labelNames: ['version', 'revision', 'buildTime', 'platform', 'nodeVersion', 'os', 'osRelease'],
}).set({
version: version.version,
revision: version.SHA,
buildTime: version.buildTime,
platform: process.release.name,
nodeVersion: process.version,
os: process.platform,
osRelease: os.release(),
}, 1);

// Collect default prometheus metrics every 10 seconds
const collectDefaultMetrics = prom.collectDefaultMetrics;
collectDefaultMetrics();

const healthEndpoint = 'health';
const metricsEndpoint = 'metrics';
const enginesEndpoint = 'engines';

// Initialize endpoint counters
const enginesCounter = new prom.Counter({ name: 'mira_api_engines_request_counter', help: 'Number of requests to /engines endpoint' });
const healthCounter = new prom.Counter({ name: 'mira_api_health_request_counter', help: 'Number of requests to /health endpoint' });
const metricsCounter = new prom.Counter({ name: 'mira_api_metrics_request_counter', help: 'Number of requests to /metrics endpoint' });

/**
* @swagger
* /health:
Expand All @@ -56,6 +41,7 @@ const enginesEndpoint = 'engines';
*/
router.get(`/${healthEndpoint}`, async (ctx) => {
logger.debug(`GET /${apiVersion}/${healthEndpoint}`);
healthCounter.inc();
ctx.body = {};
});

Expand All @@ -76,6 +62,7 @@ router.get(`/${healthEndpoint}`, async (ctx) => {
*/
router.get(`/${metricsEndpoint}`, async (ctx) => {
logger.debug(`GET /${apiVersion}/${metricsEndpoint}`);
metricsCounter.inc();
if (ctx.accepts('text')) {
ctx.body = prom.register.metrics();
} else {
Expand Down Expand Up @@ -109,6 +96,7 @@ router.get(`/${metricsEndpoint}`, async (ctx) => {
*/
router.get(`/${enginesEndpoint}`, async (ctx) => {
logger.info(`GET /${apiVersion}/${enginesEndpoint}${ctx.querystring ? `?${ctx.querystring}` : ''}`);
enginesCounter.inc();
try {
ctx.body = await engineDiscovery.list(ctx.query);
} catch (err) {
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const Config = require('./Config');

Config.init();

const metrics = require('./Metrics');
const router = require('./Routes');

logger.info(`Build info: ${JSON.stringify(version)}`);
Expand Down Expand Up @@ -57,6 +58,7 @@ process.on('uncaughtException', onUnhandledError);
process.on('unhandledRejection', onUnhandledError);

app
.use(metrics())
.use(swagger2koa.ui(document, '/openapi'))
.use(router.routes())
.use(router.allowedMethods());
Expand Down
4 changes: 4 additions & 0 deletions test/integration/integration-local.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ describe('GET /metrics', () => {
expect(res.type).to.equal('text/plain');
expect(res.text.length).to.not.equal(0);
expect(res.text).to.contain('mira_build_info');
expect(res.text).to.contain('mira_api_response_time_ms');
expect(res.text).to.contain('mira_api_engines_request_counter');
expect(res.text).to.contain('mira_api_health_request_counter');
expect(res.text).to.contain('mira_api_metrics_request_counter');
});
});

Expand Down