-
Notifications
You must be signed in to change notification settings - Fork 349
[SVLS-4148] Inject trace context into AWS Stepfunction executions #4069
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8b5a06b
df31311
288c281
c1cd88a
4f954f0
ceaf348
fbd7d7f
a5c7161
1e0e415
3cf43be
950caca
295c3a8
a4d00b5
33ee901
8e41b0d
a11cea7
9d30d3e
9b380bb
80313e5
8382a7b
b97664a
741ee94
1bd8936
17dc837
21daf7b
68edc25
1759b08
3e8358d
55abe2e
9a5c17c
0efb987
f9d10bb
3e12e32
dbbeabc
54d2042
298c174
9ddeba1
ca0d735
7fc4487
ef562f6
8260093
5192a2d
a0fd155
2ea4b27
c44dcde
9eb452b
b6145dd
51d695b
0962a9f
546535f
e5976e7
760bdb7
2642b37
558392c
88c7834
7386813
fae65ae
8948b68
b421e3a
762f43e
a3b6702
5a4a826
1e5602f
8d60bbb
86a241e
5d674ea
302e981
529547c
accd175
785d4c8
0b4c4bc
3ae086c
f81eabb
75159fa
49f7c63
f95fc9c
3bbaa4a
d297f10
8e20015
dbbe143
17470b6
247c714
4b6d789
684fb49
9adf740
01e9f1b
74bec35
75c8d98
2e840ea
679cbb6
cf26b7d
cadcd0f
c5400ea
a5c070b
3b51167
7eb415b
e3349d1
d023cf3
110f484
7011213
bb2337c
dd26219
e0763b0
cdead80
6f0cad9
ab77424
4c42897
7700a33
13914e4
78e8e34
c819350
21971fc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| 'use strict' | ||
| const Stepfunctions = require('./stepfunctions') | ||
| class Sfn extends Stepfunctions { | ||
| static get id () { return 'sfn' } | ||
| } | ||
|
|
||
| module.exports = Sfn |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| 'use strict' | ||
| const Stepfunctions = require('./stepfunctions') | ||
| class States extends Stepfunctions { | ||
| static get id () { return 'states' } | ||
| } | ||
|
|
||
| module.exports = States |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| 'use strict' | ||
| const log = require('../../../dd-trace/src/log') | ||
| const BaseAwsSdkPlugin = require('../base') | ||
|
|
||
| class Stepfunctions extends BaseAwsSdkPlugin { | ||
| static get id () { return 'stepfunctions' } | ||
|
|
||
| // This is the shape of StartExecutionInput, as defined in | ||
| // https://github.com/aws/aws-sdk-js/blob/master/apis/states-2016-11-23.normal.json | ||
| // "StartExecutionInput": { | ||
| // "type": "structure", | ||
| // "required": [ | ||
| // "stateMachineArn" | ||
| // ], | ||
| // "members": { | ||
| // "stateMachineArn": { | ||
| // "shape": "Arn", | ||
| // }, | ||
| // "name": { | ||
| // "shape": "Name", | ||
| // }, | ||
| // "input": { | ||
| // "shape": "SensitiveData", | ||
| // }, | ||
| // "traceHeader": { | ||
| // "shape": "TraceHeader", | ||
| // } | ||
| // } | ||
|
|
||
| generateTags (params, operation, response) { | ||
| if (!params) return {} | ||
| const tags = { 'resource.name': params.name ? `${operation} ${params.name}` : `${operation}` } | ||
| if (operation === 'startExecution' || operation === 'startSyncExecution') { | ||
| tags.statemachinearn = `${params.stateMachineArn}` | ||
| } | ||
| return tags | ||
| } | ||
|
|
||
| requestInject (span, request) { | ||
| const operation = request.operation | ||
| if (operation === 'startExecution' || operation === 'startSyncExecution') { | ||
| if (!request.params || !request.params.input) { | ||
| return | ||
| } | ||
|
|
||
| const input = request.params.input | ||
|
|
||
| try { | ||
| const inputObj = JSON.parse(input) | ||
| if (inputObj && typeof inputObj === 'object') { | ||
| // We've parsed the input JSON string | ||
| inputObj._datadog = {} | ||
| this.tracer.inject(span, 'text_map', inputObj._datadog) | ||
| const newInput = JSON.stringify(inputObj) | ||
| request.params.input = newInput | ||
| } | ||
|
Comment on lines
+49
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there nowhere we could do this injection where it's an object rather than a string? It would be nice if we could avoid parsing it only to convert it back to a string right after. 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question! The aws-sdk expects |
||
| } catch (e) { | ||
| log.info('Unable to treat input as JSON') | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| module.exports = Stepfunctions | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| /* eslint-disable max-len */ | ||
| 'use strict' | ||
|
|
||
| const semver = require('semver') | ||
| const agent = require('../../dd-trace/test/plugins/agent') | ||
| const { setup } = require('./spec_helpers') | ||
|
|
||
| const helloWorldSMD = { | ||
| Comment: 'A Hello World example of the Amazon States Language using a Pass state', | ||
| StartAt: 'HelloWorld', | ||
| States: { | ||
| HelloWorld: { | ||
| Type: 'Pass', | ||
| Result: 'Hello World!', | ||
| End: true | ||
| } | ||
| } | ||
| } | ||
|
|
||
| describe('Sfn', () => { | ||
| let tracer | ||
|
|
||
| withVersions('aws-sdk', ['aws-sdk', '@aws-sdk/smithy-client'], (version, moduleName) => { | ||
| let stateMachineArn | ||
| let client | ||
|
|
||
| setup() | ||
|
|
||
| before(() => { | ||
| client = getClient() | ||
| }) | ||
|
|
||
| function getClient () { | ||
| const params = { endpoint: 'http://127.0.0.1:4566', region: 'us-east-1' } | ||
| if (moduleName === '@aws-sdk/smithy-client') { | ||
| const lib = require(`../../../versions/@aws-sdk/client-sfn@${version}`).get() | ||
| const client = new lib.SFNClient(params) | ||
| return { | ||
| client, | ||
| createStateMachine: function () { | ||
| const req = new lib.CreateStateMachineCommand(...arguments) | ||
| return client.send(req) | ||
| }, | ||
| deleteStateMachine: function () { | ||
| const req = new lib.DeleteStateMachineCommand(...arguments) | ||
| return client.send(req) | ||
| }, | ||
| startExecution: function () { | ||
| const req = new lib.StartExecutionCommand(...arguments) | ||
| return client.send(req) | ||
| }, | ||
| describeExecution: function () { | ||
| const req = new lib.DescribeExecutionCommand(...arguments) | ||
| return client.send(req) | ||
| } | ||
| } | ||
| } else { | ||
| const { StepFunctions } = require(`../../../versions/aws-sdk@${version}`).get() | ||
| const client = new StepFunctions(params) | ||
| return { | ||
| client, | ||
| createStateMachine: function () { return client.createStateMachine(...arguments).promise() }, | ||
| deleteStateMachine: function () { | ||
| return client.deleteStateMachine(...arguments).promise() | ||
| }, | ||
| startExecution: function () { return client.startExecution(...arguments).promise() }, | ||
| describeExecution: function () { return client.describeExecution(...arguments).promise() } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| async function createStateMachine (name, definition, xargs) { | ||
| return client.createStateMachine({ | ||
| definition: JSON.stringify(definition), | ||
| name: name, | ||
| roleArn: 'arn:aws:iam::123456:role/test', | ||
| ...xargs | ||
| }) | ||
| } | ||
|
|
||
| async function deleteStateMachine (arn) { | ||
| return client.deleteStateMachine({ stateMachineArn: arn }) | ||
| } | ||
|
|
||
| describe('Traces', () => { | ||
| before(() => { | ||
| tracer = require('../../dd-trace') | ||
| tracer.use('aws-sdk') | ||
| }) | ||
| // aws-sdk v2 doesn't support StepFunctions below 2.7.10 | ||
| // https://github.com/aws/aws-sdk-js/blob/5dba638fd/CHANGELOG.md?plain=1#L18 | ||
| if (moduleName !== 'aws-sdk' || semver.intersects(version, '>=2.7.10')) { | ||
| beforeEach(() => { return agent.load('aws-sdk') }) | ||
| beforeEach(async () => { | ||
| const data = await createStateMachine('helloWorld', helloWorldSMD, {}) | ||
| stateMachineArn = data.stateMachineArn | ||
| }) | ||
|
|
||
| afterEach(() => { return agent.close({ ritmReset: false }) }) | ||
|
|
||
| afterEach(async () => { | ||
| await deleteStateMachine(stateMachineArn) | ||
| }) | ||
|
|
||
| it('is instrumented', async function () { | ||
| const startExecInput = { | ||
| stateMachineArn, | ||
| input: JSON.stringify({ moduleName }) | ||
| } | ||
| const expectSpanPromise = agent.use(traces => { | ||
| const span = traces[0][0] | ||
| expect(span).to.have.property('resource', 'startExecution') | ||
| expect(span.meta).to.have.property('statemachinearn', stateMachineArn) | ||
| }) | ||
|
|
||
| const resp = await client.startExecution(startExecInput) | ||
|
|
||
| const result = await client.describeExecution({ executionArn: resp.executionArn }) | ||
| const sfInput = JSON.parse(result.input) | ||
| expect(sfInput).to.have.property('_datadog') | ||
| expect(sfInput._datadog).to.have.property('x-datadog-trace-id') | ||
| expect(sfInput._datadog).to.have.property('x-datadog-parent-id') | ||
| return expectSpanPromise.then(() => {}) | ||
| }) | ||
| } | ||
| }) | ||
| }) | ||
| }) |
Uh oh!
There was an error while loading. Please reload this page.