@instana/core
Version:
Core library for Instana's Node.js packages
127 lines (105 loc) • 4.11 kB
JavaScript
/*
* (c) Copyright IBM Corp. 2021
* (c) Copyright Instana Inc. and contributors 2021
*/
;
const shimmer = require('../../../../shimmer');
const hook = require('../../../../../util/hook');
const { getFunctionArguments } = require('../../../../../util/function_arguments');
/** @type {Array.<import('./instana_aws_product').InstanaAWSProduct}> */
const awsProducts = [
//
require('./dynamodb'),
require('./s3'),
require('./sqs'),
require('./kinesis'),
require('./sns'),
require('./lambda')
];
const awsProductInstances = [];
const sqsConsumer = require('./sqs-consumer');
/** @type {Object.<string, import('./instana_aws_product').InstanaAWSProduct} */
const operationMap = {};
let isActive = false;
exports.init = function init(config) {
awsProducts.forEach(AwsProductClass => {
const awsProductInstance = new AwsProductClass(config);
awsProductInstances.push(awsProductInstance);
Object.assign(operationMap, awsProductInstance.getOperations());
// NOTE: each aws product can have it's own init fn to wrap or unwrap specific functions
if (awsProductInstance.init) {
awsProductInstance.init(hook, shimmer);
}
});
sqsConsumer.init();
/**
* https://github.com/aws/aws-sdk-js-v3/releases/tag/v3.1046.0
*/
hook.onModuleLoad('@smithy/core/client', instrumentGlobalSmithy);
/**
* @aws-sdk/smithly-client >= 3.36.0 changed how the dist structure gets delivered
* https://github.com/aws/aws-sdk-js-v3/blob/main/packages/smithy-client/CHANGELOG.md#3360-2021-10-08
* @aws-sdk/smithly-client is a subdependency of any @aws-sdk/* package
*/
hook.onFileLoad(/@aws-sdk\/smithy-client\/dist-cjs\/client\.js/, instrumentGlobalSmithy);
/**
* @aws-sdk/smithly-client < 3.36.0
*/
hook.onFileLoad(/@aws-sdk\/smithy-client\/dist\/cjs\/client\.js/, instrumentGlobalSmithy);
/**
* @aws-sdk/smithly-client > 3.36.0
*/
hook.onModuleLoad('@smithy/smithy-client', instrumentGlobalSmithy);
};
exports.isActive = function () {
return isActive;
};
// NOTE: you currently can only disable the whole AWS SDK v3
exports.activate = function activate() {
isActive = true;
};
exports.deactivate = function deactivate() {
isActive = false;
};
/**
* The require hook can run once while `exports` is still `{}` (cyclic CJS load); `exports` is then the same object
* Node fills in later. Defer wrapping until after the current synchronous load completes.
*/
function instrumentGlobalSmithy(exports) {
const tryWrap = () => {
if (typeof exports.Client === 'function' && exports.Client.prototype) {
shimmer.wrap(exports.Client.prototype, 'send', shimSmithySend);
return true;
}
return false;
};
if (!tryWrap()) {
setImmediate(() => {
tryWrap();
});
}
return exports;
}
function shimSmithySend(originalSend) {
return function () {
const self = this;
const smithySendArgs = getFunctionArguments(arguments);
const command = smithySendArgs[0];
const serviceId = self.config && self.config.serviceId;
let awsProduct = serviceId && awsProductInstances.find(aws => aws.getServiceIdName() === serviceId.toLowerCase());
if (awsProduct && awsProduct.supportsOperation(command.constructor.name)) {
return awsProduct.instrumentedSmithySend(self, isActive, originalSend, smithySendArgs);
} else {
// This logic should not be used in AWS SDK v4. All AWS SDK v4 instrumentations must use the new approach
// introduced in https://github.com/instana/nodejs/pull/838 for Kinesis. That is: Do not use an explicit
// operationsInfo/operationsMap that restricts the traced operations to a subset of possible operations.
// Instead, allow all operations to be traced using the operation name from `command.constructor.name`
// for span.data.$spanName.op.
awsProduct = operationMap[smithySendArgs[0].constructor.name];
if (awsProduct) {
return awsProduct.instrumentedSmithySend(self, isActive, originalSend, smithySendArgs);
}
return originalSend.apply(self, smithySendArgs);
}
};
}