in lib/instrumentation/modules/@smithy/smithy-client.js [106:198]
module.exports = function (mod, agent, { name, version, enabled }) {
if (!enabled) return mod;
// As of `@aws-sdk/*@3.363.0` the underlying smithy-client is under the
// `@smithy/` npm org.
if (
name === '@smithy/smithy-client' &&
!semver.satisfies(version, '>=1 <5')
) {
agent.logger.debug(
'cannot instrument @aws-sdk/client-*: @smithy/smithy-client version %s not supported',
version,
);
return mod;
} else if (
name === '@aws-sdk/smithy-client' &&
!semver.satisfies(version, '>=3 <4')
) {
agent.logger.debug(
'cannot instrument @aws-sdk/client-*: @aws-sdk/smithy-client version %s not supported',
version,
);
return mod;
}
shimmer.wrap(mod.Client.prototype, 'send', function (orig) {
return function _wrappedSmithyClientSend() {
const clientName = this.constructor && this.constructor.name;
const clientConfig = clientsConfig[clientName];
if (!clientConfig) {
return orig.apply(this, arguments);
}
if (!this[elasticAPMMiddlewares]) {
const factory = clientConfig && clientConfig.factory;
const middlewares =
typeof factory === 'function' ? factory(this, agent) : [];
// We do the instrumentation by leveraging the middleware mechanism provided by the
// middlewareStack property of the Client instance. We add the instrumentation middlewares
// once at the client level so they persist for the whole life of the client instance
// https://github.com/aws/aws-sdk-js-v3/tree/main/packages/middleware-stack
this[elasticAPMMiddlewares] = middlewares;
for (const item of this[elasticAPMMiddlewares]) {
this.middlewareStack.add(item.middleware, item.options);
}
}
const command = arguments[0];
if (clientConfig.shouldIgnoreCommand(command, agent._conf)) {
return orig.apply(this, arguments);
}
const opName = opNameFromCommandName(command.constructor.name);
const name = clientConfig.NAME + ' ' + opName;
const ins = agent._instrumentation;
const span = ins.createSpan(
name,
clientConfig.TYPE,
clientConfig.SUBTYPE,
opName,
{ exitSpan: true },
);
if (!span) {
return orig.apply(this, arguments);
}
// Run context notes: The `orig` should run in the context of the S3 span,
// because that is the point. The user's callback `cb` should run outside of
// the S3 span.
const parentRunContext = ins.currRunContext();
const spanRunContext = parentRunContext.enterSpan(span);
// Although the client consumer may use the Promise API `S3Client.send(command).then(...)`
// the clients may make use of the callback parameter on the super class method (SmithyClient)
// therefore we need to have this check
const cb = arguments[arguments.length - 1];
if (typeof cb === 'function') {
arguments[arguments.length - 1] = ins.bindFunctionToRunContext(
parentRunContext,
cb,
);
}
return ins.withRunContext(spanRunContext, orig, this, ...arguments);
};
});
return mod;
};