/**
* Capture module.
* @module capture
*/
var contextUtils = require('./context_utils');
var logger = require('./logger');
/**
* Wrap to automatically capture information for the segment.
* @param {string} name - The name of the new subsegment.
* @param {function} fcn - The function context to wrap. Can take a single 'subsegment' argument.
* @param {Segment|Subsegment} [parent] - The parent for the new subsegment, for manual mode.
* @alias module:capture.captureFunc
* @return {*} - Returns the result if any by executing the provided function.
*/
var captureFunc = function captureFunc(name, fcn, parent) {
validate(name, fcn);
var current, executeFcn;
var parentSeg = contextUtils.resolveSegment(parent);
if (!parentSeg) {
logger.getLogger().warn('Failed to capture function.');
return fcn();
}
current = parentSeg.addNewSubsegment(name);
executeFcn = captureFcn(fcn, current);
try {
const response = executeFcn(current);
current.close();
return response;
} catch (e) {
current.close(e);
throw (e);
}
};
/**
* Wrap to automatically capture information for the sub/segment. You must close the segment
* manually from within the function.
* @param {string} name - The name of the new subsegment.
* @param {function} fcn - The function context to wrap. Must take a single 'subsegment' argument and call 'subsegment.close([optional error])' when the async function completes.
* @param {Segment|Subsegment} [parent] - The parent for the new subsegment, for manual mode.
* @alias module:capture.captureAsyncFunc
* @return {*} - Returns a promise by executing the provided async function.
*/
var captureAsyncFunc = function captureAsyncFunc(name, fcn, parent) {
validate(name, fcn);
var current, executeFcn;
var parentSeg = contextUtils.resolveSegment(parent);
if (!parentSeg) {
logger.getLogger().warn('Failed to capture async function.');
return fcn();
}
current = parentSeg.addNewSubsegment(name);
executeFcn = captureFcn(fcn, current);
try {
return executeFcn(current);
} catch (e) {
current.close(e);
throw (e);
}
};
/**
* Wrap to automatically capture information for the sub/segment. This wraps the callback and returns a function.
* when executed, all arguments are passed through accordingly. An additional argument is appended to gain access to the newly created subsegment.
* For this reason, always call the captured callback with the full list of arguments.
* @param {string} name - The name of the new subsegment.
* @param {function} fcn - The function context to wrap. Can take a single 'subsegment' argument.
* @param {Segment|Subsegment} [parent] - The parent for the new subsegment, for manual mode.
* @alias module:capture.captureCallbackFunc
*/
var captureCallbackFunc = function captureCallbackFunc(name, fcn, parent) {
validate(name, fcn);
var base = contextUtils.resolveSegment(parent);
if (!base) {
logger.getLogger().warn('Failed to capture callback function.');
return fcn;
}
base.incrementCounter();
return function() {
var parentSeg = contextUtils.resolveSegment(parent);
var args = Array.prototype.slice.call(arguments);
captureFunc(name, fcn.bind.apply(fcn, [null].concat(args)), parentSeg);
base.decrementCounter();
}.bind(this);
};
function captureFcn(fcn, current) {
var executeFcn;
if (contextUtils.isAutomaticMode()) {
var session = contextUtils.getNamespace();
var contextFcn = function() {
var value;
session.run(function() {
contextUtils.setSegment(current);
value = fcn(current);
});
return value;
};
executeFcn = contextFcn;
} else {
executeFcn = fcn;
}
return executeFcn;
}
function validate(name, fcn) {
var error;
if (!name || typeof name !== 'string') {
error = 'Param "name" must be a non-empty string.';
logger.getLogger().error(error);
throw new Error(error);
} else if (typeof fcn !== 'function') {
error = 'Param "fcn" must be a function.';
logger.getLogger().error(error);
throw new Error(error);
}
}
module.exports.captureFunc = captureFunc;
module.exports.captureAsyncFunc = captureAsyncFunc;
module.exports.captureCallbackFunc = captureCallbackFunc;