forked from elastic/apm-agent-nodejs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: sns instrumentation (elastic#2157)
* Implements implementation of Amazon SNS for the v2 APIs elastic#1955 Co-authored-by: Trent Mick <[email protected]>
- Loading branch information
1 parent
ef3a09f
commit 9826911
Showing
6 changed files
with
613 additions
and
2 deletions.
There are no files selected for viewing
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
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
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
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,151 @@ | ||
const constants = require('../../../constants') | ||
|
||
const TYPE = 'messaging' | ||
const SUBTYPE = 'sns' | ||
const ACTION = 'publish' | ||
const PHONE_NUMBER = '<PHONE_NUMBER>' | ||
|
||
function getArnOrPhoneNumberFromRequest (request) { | ||
let arn = request && request.params && request.params.TopicArn | ||
if (!arn) { | ||
arn = request && request.params && request.params.TargetArn | ||
} | ||
if (!arn) { | ||
arn = request && request.params && request.params.PhoneNumber | ||
} | ||
return arn | ||
} | ||
|
||
function getRegionFromRequest (request) { | ||
return request && request.service && | ||
request.service.config && request.service.config.region | ||
} | ||
|
||
function getSpanNameFromRequest (request) { | ||
const topicName = getDestinationNameFromRequest(request) | ||
return `SNS PUBLISH to ${topicName}` | ||
} | ||
|
||
function getMessageContextFromRequest (request) { | ||
return { | ||
queue: { | ||
name: getDestinationNameFromRequest(request) | ||
} | ||
} | ||
} | ||
|
||
function getAddressFromRequest (request) { | ||
return request && request.service && request.service.endpoint && | ||
request.service.endpoint.hostname | ||
} | ||
|
||
function getPortFromRequest (request) { | ||
return request && request.service && request.service.endpoint && | ||
request.service.endpoint.port | ||
} | ||
|
||
function getMessageDestinationContextFromRequest (request) { | ||
return { | ||
address: getAddressFromRequest(request), | ||
port: getPortFromRequest(request), | ||
service: { | ||
resource: `${SUBTYPE}/${getDestinationNameFromRequest(request)}`, | ||
type: TYPE, | ||
name: SUBTYPE | ||
}, | ||
cloud: { | ||
region: getRegionFromRequest(request) | ||
} | ||
} | ||
} | ||
|
||
function getDestinationNameFromRequest (request) { | ||
const phoneNumber = request && request.params && request.params.PhoneNumber | ||
if (phoneNumber) { | ||
return PHONE_NUMBER | ||
} | ||
|
||
const topicArn = request && request.params && request.params.TopicArn | ||
const targetArn = request && request.params && request.params.TargetArn | ||
|
||
if (topicArn) { | ||
const parts = topicArn.split(':') | ||
const topicName = parts.pop() | ||
return topicName | ||
} | ||
|
||
if (targetArn) { | ||
const fullName = targetArn.split(':').pop() | ||
if (fullName.lastIndexOf('/') !== -1) { | ||
return fullName.substring(0, fullName.lastIndexOf('/')) | ||
} else { | ||
return fullName | ||
} | ||
} | ||
} | ||
|
||
function shouldIgnoreRequest (request, agent) { | ||
if (request.operation !== 'publish') { | ||
return true | ||
} | ||
|
||
// is the named topic on our ignore list? | ||
if (agent._conf && agent._conf.ignoreMessageQueuesRegExp) { | ||
const queueName = getArnOrPhoneNumberFromRequest(request) | ||
if (queueName) { | ||
for (const rule of agent._conf.ignoreMessageQueuesRegExp) { | ||
if (rule.test(queueName)) { | ||
return true | ||
} | ||
} | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
function instrumentationSns (orig, origArguments, request, AWS, agent, { version, enabled }) { | ||
const type = TYPE | ||
const subtype = SUBTYPE | ||
const action = ACTION | ||
|
||
if (shouldIgnoreRequest(request, agent)) { | ||
return orig.apply(request, origArguments) | ||
} | ||
|
||
const name = getSpanNameFromRequest(request) | ||
const span = agent.startSpan(name, type, subtype, action) | ||
if (!span) { | ||
return orig.apply(request, origArguments) | ||
} | ||
|
||
span.setDestinationContext(getMessageDestinationContextFromRequest(request)) | ||
span.setMessageContext(getMessageContextFromRequest(request)) | ||
|
||
request.on('complete', function (response) { | ||
if (response && response.error) { | ||
const errOpts = { | ||
skipOutcome: true | ||
} | ||
agent.captureError(response.error, errOpts) | ||
span._setOutcomeFromErrorCapture(constants.OUTCOME_FAILURE) | ||
} | ||
|
||
// we'll need to manually mark this span as async. The actual async hop | ||
// is captured by the agent's async hooks instrumentation | ||
span.sync = false | ||
span.end() | ||
}) | ||
|
||
return orig.apply(request, origArguments) | ||
} | ||
|
||
module.exports = { | ||
instrumentationSns, | ||
|
||
// exported for testing | ||
getSpanNameFromRequest, | ||
getDestinationNameFromRequest, | ||
getMessageDestinationContextFromRequest, | ||
getArnOrPhoneNumberFromRequest | ||
} |
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,46 @@ | ||
'use strict' | ||
module.exports = { | ||
publish: { | ||
response: `<?xml version="1.0"?> | ||
<PublishResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/"> | ||
<PublishResult> | ||
<MessageId>32a3b682-ce0c-5b2a-b97f-efe5112e9f06</MessageId> | ||
</PublishResult> | ||
<ResponseMetadata> | ||
<RequestId>8e87dc3a-07f7-54f0-ae0d-855dd8d5f0dc</RequestId> | ||
</ResponseMetadata> | ||
</PublishResponse>`, | ||
httpStatusCode: 200 | ||
}, | ||
publishNoTopic: { | ||
response: `<?xml version="1.0"?> | ||
<ErrorResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/"> | ||
<Error> | ||
<Type>Sender</Type> | ||
<Code>NotFound</Code> | ||
<Message>Topic does not exist</Message> | ||
</Error> | ||
<RequestId>02672fe4-577a-5c2a-9a11-7683bd8777e1</RequestId> | ||
</ErrorResponse>`, | ||
httpStatusCode: 404 | ||
}, | ||
listTopics: { | ||
response: `<?xml version="1.0"?> | ||
<ListTopicsResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/"> | ||
<ListTopicsResult> | ||
<Topics> | ||
<member> | ||
<TopicArn>arn:aws:sns:us-west-2:111111111111:topic-name</TopicArn> | ||
</member> | ||
<member> | ||
<TopicArn>arn:aws:sns:us-west-2:111111111111:dynamodb</TopicArn> | ||
</member> | ||
</Topics> | ||
</ListTopicsResult> | ||
<ResponseMetadata> | ||
<RequestId>1cb1f1f2-48fa-523b-a01a-a895b59d244b</RequestId> | ||
</ResponseMetadata> | ||
</ListTopicsResponse>`, | ||
httpStatusCode: 200 | ||
} | ||
} |
Oops, something went wrong.