openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
158 lines (137 loc) • 4.6 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.recordTransactionMetrics = recordTransactionMetrics;
exports.calculateMetrics = calculateMetrics;
var _model = require('./model');
var _moment = require('moment');
var _moment2 = _interopRequireDefault(_moment);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const TRANSACTION_STATUS_KEYS = {
Processing: 'processing',
Successful: 'successful',
Completed: 'completed',
'Completed with error(s)': 'completedWithErrors',
Failed: 'failed'
};
const METRIC_UPDATE_OPTIONS = { upsert: true, setDefaultsOnInsert: true };
async function recordTransactionMetric(fields, update) {
return _model.MetricModel.updateOne(fields, Object.assign({}, update, { $setOnInsert: fields }), METRIC_UPDATE_OPTIONS);
}
async function recordTransactionMetrics(transaction) {
if (!transaction.response) {
// Don't record metrics if there is no response i.e. an error
return;
}
const responseTime = transaction.response.timestamp - transaction.request.timestamp;
const statusKey = TRANSACTION_STATUS_KEYS[transaction.status];
const update = {
$inc: {
requests: 1,
responseTime,
[statusKey]: 1
},
$min: {
minResponseTime: responseTime
},
$max: {
maxResponseTime: responseTime
}
// Update metrics for the minute bucket
};const minuteUpdate = recordTransactionMetric({
type: _model.METRIC_TYPE_MINUTE,
startTime: (0, _moment2.default)(transaction.request.timestamp).startOf('minute').toDate(),
channelID: transaction.channelID
}, update);
// Update metrics for the hour bucket
const hourUpdate = recordTransactionMetric({
type: _model.METRIC_TYPE_HOUR,
startTime: (0, _moment2.default)(transaction.request.timestamp).startOf('hour').toDate(),
channelID: transaction.channelID
}, update);
// Update metrics for the day bucket
const dayUpdate = recordTransactionMetric({
type: _model.METRIC_TYPE_DAY,
startTime: (0, _moment2.default)(transaction.request.timestamp).startOf('day').toDate(),
channelID: transaction.channelID
}, update);
await Promise.all([minuteUpdate, hourUpdate, dayUpdate]);
}
const METRICS_GROUPINGS = {
requests: { $sum: '$requests' },
responseTime: { $sum: '$responseTime' },
minResponseTime: { $min: '$minResponseTime' },
maxResponseTime: { $max: '$maxResponseTime' },
successful: { $sum: '$successful' },
failed: { $sum: '$failed' },
processing: { $sum: '$processing' },
completed: { $sum: '$completed' },
completedWithErrors: { $sum: '$completedWithErrors' }
/**
* Calculate metrics for all channels, filtered by the given filters.
*
* @param {Object} filters
* @param {Date} filters.startDate Start date
* @param {Date} filters.endDate End date
* @param {Object[]} filters.channels Array of channel IDs
* @param {String} [filters.timeSeries] Time period
* @param {boolean} [groupByChannel=true] Whether to group metrics by channel
*/
};async function calculateMetrics(filters, groupByChannel = true) {
const pipeline = [{
$match: {
startTime: {
$gte: filters.startDate,
$lte: filters.endDate
},
channelID: {
$in: filters.channels
},
type: mapTimeSeriesToMetricType(filters.timeSeries)
}
}];
if (!groupByChannel) {
// Combine metrics for different channels if not grouping by channel
pipeline.push({
$group: Object.assign({}, METRICS_GROUPINGS, {
_id: {
startTime: '$startTime',
type: '$type'
},
startTime: { $first: '$startTime' },
type: { $first: '$type' }
})
});
}
if (!filters.timeSeries) {
// Combine metrics by channel if not grouping by time series
pipeline.push({
$group: Object.assign({}, METRICS_GROUPINGS, {
_id: {
channelID: '$channelID'
},
channelID: { $first: '$channelID' }
})
});
}
pipeline.push({ $sort: { startTime: 1, channelID: 1 } });
return _model.MetricModel.aggregate(pipeline);
}
function mapTimeSeriesToMetricType(timeSeries) {
switch (timeSeries) {
case 'minute':
return _model.METRIC_TYPE_MINUTE;
case 'hour':
return _model.METRIC_TYPE_HOUR;
case 'day':
case 'week':
case 'month':
case 'year':
return _model.METRIC_TYPE_DAY;
default:
// Should be the lowest metric type which does not expire
return _model.METRIC_TYPE_HOUR;
}
}
//# sourceMappingURL=metrics.js.map