openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
191 lines (171 loc) • 4.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.recordTransactionMetrics = recordTransactionMetrics;
exports.calculateMetrics = calculateMetrics;
var _model = require("./model");
var _moment = _interopRequireDefault(require("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 || !transaction.response.timestamp || !(transaction.response.timestamp instanceof Date)) {
// Don't record metrics if there is no response i.e. an error
// or if the response does not have a timestamp
// or if the timestamp isnt an instance of Date
return;
}
const responseTime = transaction.response.timestamp.getTime() - transaction.request.timestamp.getTime();
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, _moment.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, _moment.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, _moment.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