-
Notifications
You must be signed in to change notification settings - Fork 400
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Migrated @newrelic/aws-sdk into agent repo (#2161)
- Loading branch information
Showing
101 changed files
with
14,615 additions
and
2,728 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Copyright 2020 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
const InstrumentationDescriptor = require('../../instrumentation-descriptor') | ||
|
||
const instrumentations = [ | ||
{ | ||
type: InstrumentationDescriptor.TYPE_CONGLOMERATE, | ||
moduleName: 'aws-sdk', | ||
onRequire: require('./v2/instrumentation') | ||
}, | ||
{ | ||
type: InstrumentationDescriptor.TYPE_CONGLOMERATE, | ||
moduleName: '@aws-sdk/smithy-client', | ||
onRequire: require('./v3/smithy-client'), | ||
shimName: 'aws-sdk' | ||
}, | ||
{ | ||
type: InstrumentationDescriptor.TYPE_CONGLOMERATE, | ||
moduleName: '@smithy/smithy-client', | ||
onRequire: require('./v3/smithy-client'), | ||
shimName: 'aws-sdk' | ||
} | ||
] | ||
|
||
module.exports = instrumentations |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Copyright 2020 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
const UNKNOWN = 'Unknown' | ||
const { | ||
params: { DatastoreParameters } | ||
} = require('../../shim/specs') | ||
|
||
function grabLastUrlSegment(url = '/') { | ||
// cast URL as string, and an empty | ||
// string for null, undefined, NaN etc. | ||
url = '' + (url || '/') | ||
const lastSlashIndex = url.lastIndexOf('/') | ||
return url.substr(lastSlashIndex + 1) | ||
} | ||
|
||
/** | ||
* Retrieves the db segment params from endpoint and command parameters | ||
* | ||
* @param {Object} endpoint instance of ddb endpoint | ||
* @param {Object} params parameters passed to a ddb command | ||
* @returns {Object} | ||
*/ | ||
function setDynamoParameters(endpoint, params) { | ||
return new DatastoreParameters({ | ||
host: endpoint && (endpoint.host || endpoint.hostname), | ||
port_path_or_id: (endpoint && endpoint.port) || 443, | ||
collection: (params && params.TableName) || UNKNOWN | ||
}) | ||
} | ||
|
||
module.exports = { | ||
grabLastUrlSegment, | ||
setDynamoParameters | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
* Copyright 2020 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
|
||
const UNKNOWN = 'Unknown' | ||
const symbols = require('../../../symbols') | ||
const InstrumentationDescriptor = require('../../../instrumentation-descriptor') | ||
|
||
function validate(shim, AWS) { | ||
if (!shim.isFunction(AWS.NodeHttpClient)) { | ||
shim.logger.debug('Could not find NodeHttpClient, not instrumenting.') | ||
return false | ||
} | ||
if (!shim.isFunction(AWS.Service) || !shim.isFunction(AWS.Service.prototype.makeRequest)) { | ||
shim.logger.debug('Could not find AWS.Service#makeRequest, not instrumenting.') | ||
return false | ||
} | ||
return true | ||
} | ||
|
||
function instrument(shim, AWS) { | ||
shim.wrap(AWS.NodeHttpClient.prototype, 'handleRequest', wrapHandleRequest) | ||
shim.wrapReturn(AWS.Service.prototype, 'makeRequest', wrapMakeRequest) | ||
} | ||
|
||
function wrapHandleRequest(shim, handleRequest) { | ||
return function wrappedHandleRequest(httpRequest) { | ||
if (httpRequest) { | ||
if (!httpRequest.headers) { | ||
httpRequest.headers = Object.create(null) | ||
} | ||
httpRequest.headers[symbols.disableDT] = true | ||
} else { | ||
shim.logger.debug('Unknown arguments to AWS.NodeHttpClient#handleRequest!') | ||
} | ||
|
||
return handleRequest.apply(this, arguments) | ||
} | ||
} | ||
|
||
function wrapMakeRequest(shim, fn, name, request) { | ||
if (!request) { | ||
shim.logger.trace('No request object returned from Service#makeRequest') | ||
return | ||
} | ||
|
||
const service = getServiceName(this) | ||
const region = this?.config?.region | ||
request.on('complete', function onAwsRequestComplete() { | ||
const httpRequest = request.httpRequest && request.httpRequest.stream | ||
const segment = shim.getSegment(httpRequest) | ||
if (!httpRequest || !segment) { | ||
shim.logger.trace('No segment found for request, not extracting information.') | ||
return | ||
} | ||
|
||
const requestRegion = request?.httpRequest?.region | ||
const requestId = request?.response?.requestId | ||
|
||
segment.addAttribute('aws.operation', request.operation || UNKNOWN) | ||
segment.addAttribute('aws.requestId', requestId || UNKNOWN) | ||
segment.addAttribute('aws.service', service || UNKNOWN) | ||
segment.addAttribute('aws.region', requestRegion || region || UNKNOWN) | ||
}) | ||
|
||
shim.wrap(request, 'promise', function wrapPromiseFunc(shim, original) { | ||
const activeSegment = shim.getActiveSegment() | ||
|
||
return function wrappedPromiseFunc() { | ||
if (!activeSegment) { | ||
return original.apply(this, arguments) | ||
} | ||
|
||
const promise = shim.applySegment(original, activeSegment, false, this, arguments) | ||
|
||
return shim.bindPromise(promise, activeSegment) | ||
} | ||
}) | ||
} | ||
|
||
function getServiceName(service) { | ||
if (service.api && (service.api.abbreviation || service.api.serviceId)) { | ||
return service.api.abbreviation || service.api.serviceId | ||
} | ||
|
||
// In theory, getting the `constructor.prototype` should be redundant with | ||
// checking `service`. However, the aws-sdk dynamically generates classes and | ||
// doing this deep check was the recommended method by the maintainers. | ||
const constructor = service.constructor | ||
const api = constructor && constructor.prototype && constructor.prototype.api | ||
if (api) { | ||
return api.abbreviation || api.serviceId | ||
} | ||
return null | ||
} | ||
|
||
module.exports = { | ||
name: 'core', | ||
type: InstrumentationDescriptor.TYPE_GENERIC, | ||
validate, | ||
instrument | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
* Copyright 2020 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
const InstrumentationDescriptor = require('../../../instrumentation-descriptor') | ||
|
||
const DDB_OPERATIONS = [ | ||
'putItem', | ||
'getItem', | ||
'updateItem', | ||
'deleteItem', | ||
'createTable', | ||
'deleteTable', | ||
'query', | ||
'scan' | ||
] | ||
|
||
const DOC_CLIENT_OPERATIONS = [ | ||
'get', | ||
'put', | ||
'update', | ||
'delete', | ||
'batchGet', | ||
'batchWrite', | ||
'transactGet', | ||
'transactWrite', | ||
'query', | ||
'scan' | ||
] | ||
const { | ||
OperationSpec, | ||
params: { DatastoreParameters } | ||
} = require('../../../shim/specs') | ||
|
||
const { setDynamoParameters } = require('../util') | ||
|
||
function instrument(shim, AWS) { | ||
shim.setDatastore(shim.DYNAMODB) | ||
|
||
// DynamoDB's service API methods are dynamically generated | ||
// in the constructor so we have to wrap the return. | ||
shim.wrapReturn(AWS, 'DynamoDB', function wrapDynamo(shim, fn, name, ddb) { | ||
shim.recordOperation( | ||
ddb, | ||
DDB_OPERATIONS, | ||
function wrapMethod(shim, original, operationName, args) { | ||
const params = args[0] | ||
|
||
return new OperationSpec({ | ||
name: operationName, | ||
parameters: setDynamoParameters(this.endpoint, params), | ||
callback: shim.LAST, | ||
opaque: true | ||
}) | ||
} | ||
) | ||
}) | ||
|
||
// DocumentClient's API is predefined so we can instrument the prototype. | ||
// DocumentClient does defer to DynamoDB but it also does enough individual | ||
// steps for the request we want to hide that instrumenting specifically and | ||
// setting to opaque is currently required. | ||
const docClientProto = AWS.DynamoDB.DocumentClient.prototype | ||
shim.recordOperation( | ||
docClientProto, | ||
DOC_CLIENT_OPERATIONS, | ||
function wrapOperation(shim, original, operationName, args) { | ||
const params = args[0] | ||
const dynamoOperation = this.serviceClientOperationsMap[operationName] | ||
|
||
// DocumentClient can be defined with a different service such as AmazonDaxClient. | ||
// In these cases, an endpoint property may not exist. In the DAX case, | ||
// the eventual cached endpoint to be hit is not known at this point. | ||
const endpoint = this.service && this.service.endpoint | ||
|
||
return new OperationSpec({ | ||
name: dynamoOperation, | ||
parameters: new DatastoreParameters({ | ||
host: endpoint?.host, | ||
port_path_or_id: endpoint?.port, | ||
collection: params?.TableName || 'Unknown' | ||
}), | ||
callback: shim.LAST, | ||
opaque: true | ||
}) | ||
} | ||
) | ||
} | ||
|
||
module.exports = { | ||
name: 'dynamodb', | ||
type: InstrumentationDescriptor.TYPE_DATASTORE, | ||
instrument, | ||
validate: (shim, AWS) => { | ||
if (!shim.isFunction(AWS.DynamoDB)) { | ||
shim.logger.debug('Could not find DynamoDB, not instrumenting.') | ||
return false | ||
} | ||
return true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* Copyright 2020 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
|
||
/** | ||
* Series of tests to determine if the library | ||
* has the features needed to provide instrumentation | ||
* @param AWS | ||
*/ | ||
const instrumentationSupported = function instrumentationSupported(AWS) { | ||
// instrumentation requires the serviceClientOperationsMap property | ||
/* eslint-disable-next-line */ | ||
if ( | ||
!AWS || | ||
!AWS.DynamoDB || | ||
!AWS.DynamoDB.DocumentClient || | ||
!AWS.DynamoDB.DocumentClient.prototype || | ||
!AWS.DynamoDB.DocumentClient.prototype.serviceClientOperationsMap | ||
) { | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
module.exports = { | ||
instrumentationSupported | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* Copyright 2020 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
|
||
const INSTRUMENTATIONS = [ | ||
require('./core'), | ||
require('./dynamodb'), | ||
require('./sqs'), | ||
require('./sns') | ||
] | ||
|
||
const helper = require('./instrumentation-helper') | ||
|
||
module.exports = function initialize(shim, AWS) { | ||
if (!helper.instrumentationSupported(AWS)) { | ||
return false | ||
} | ||
// Validate every instrumentation before attempting to run any of them. | ||
for (const instrumentation of INSTRUMENTATIONS) { | ||
if (!instrumentation.validate(shim, AWS)) { | ||
return false | ||
} | ||
} | ||
|
||
for (const instrumentation of INSTRUMENTATIONS) { | ||
const subshim = shim.makeSpecializedShim(instrumentation.type, instrumentation.name) | ||
instrumentation.instrument(subshim, AWS) | ||
} | ||
|
||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright 2020 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
'use strict' | ||
const { MessageSpec } = require('../../../shim/specs') | ||
const InstrumentationDescriptor = require('../../../instrumentation-descriptor') | ||
|
||
module.exports = { | ||
name: 'sns', | ||
type: InstrumentationDescriptor.TYPE_MESSAGE, | ||
validate: (shim, AWS) => { | ||
if (!shim.isFunction(AWS.SNS)) { | ||
shim.logger.debug('Could not find SNS, not instrumenting.') | ||
return false | ||
} | ||
return true | ||
}, | ||
instrument | ||
} | ||
|
||
function instrument(shim, AWS) { | ||
shim.setLibrary(shim.SNS) | ||
|
||
shim.wrapReturn(AWS, 'SNS', function wrapSns(shim, original, name, sns) { | ||
shim.recordProduce(sns, 'publish', wrapPublish) | ||
}) | ||
} | ||
|
||
function wrapPublish(shim, original, name, args) { | ||
return new MessageSpec({ | ||
callback: shim.LAST, | ||
destinationName: getDestinationName(args[0]), | ||
destinationType: shim.TOPIC, | ||
opaque: true | ||
}) | ||
} | ||
|
||
function getDestinationName({ TopicArn, TargetArn }) { | ||
return TopicArn || TargetArn || 'PhoneNumber' // We don't want the value of PhoneNumber | ||
} |
Oops, something went wrong.