Skip to content

Commit 5eb97ef

Browse files
fix(core): capture command data for SDK v3 clients (#611)
* fix(core): capture additional command data with SDK v3 * adds unit tests for abandoned PR #527 * adds output mapping to test * removes leftover util import * requested changes on #611 --------- Co-authored-by: SergeiPoluektov <[email protected]>
1 parent e32dd95 commit 5eb97ef

File tree

2 files changed

+93
-28
lines changed

2 files changed

+93
-28
lines changed

packages/core/lib/patchers/aws3_p.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const buildAttributesFromMetadata = async (
3939
service: string,
4040
operation: string,
4141
region: string,
42+
commandInput: any,
4243
res: any | null,
4344
error: SdkError | null,
4445
): Promise<[ServiceSegment, HttpResponse]> => {
@@ -49,8 +50,10 @@ const buildAttributesFromMetadata = async (
4950
extendedRequestId,
5051
requestId,
5152
retryCount: attempts,
53+
data: res?.output,
5254
request: {
5355
operation,
56+
params: commandInput,
5457
httpRequest: {
5558
region,
5659
statusCode,
@@ -93,11 +96,13 @@ function addFlags(http: HttpResponse, subsegment: Subsegment, err?: SdkError): v
9396
const getXRayMiddleware = (config: RegionResolvedConfig, manualSegment?: SegmentLike): BuildMiddleware<any, any> => (next: any, context: any) => async (args: any) => {
9497
const segment = contextUtils.isAutomaticMode() ? contextUtils.resolveSegment() : manualSegment;
9598
const {clientName, commandName} = context;
96-
const operation: string = commandName.slice(0, -7); // Strip trailing "Command" string
99+
const commandInput = args?.input ?? {};
100+
const commandOperation: string = commandName.slice(0, -7); // Strip trailing "Command" string
101+
const operation: string = commandOperation.charAt(0).toLowerCase() + commandOperation.slice(1);
97102
const service: string = clientName.slice(0, -6); // Strip trailing "Client" string
98103

99104
if (!segment) {
100-
const output = service + '.' + operation.charAt(0).toLowerCase() + operation.slice(1);
105+
const output = service + '.' + operation;
101106

102107
if (!contextUtils.isAutomaticMode()) {
103108
logger.getLogger().info('Call ' + output + ' requires a segment object' +
@@ -148,6 +153,7 @@ const getXRayMiddleware = (config: RegionResolvedConfig, manualSegment?: Segment
148153
service,
149154
operation,
150155
await config.region(),
156+
commandInput,
151157
res,
152158
null,
153159
);
@@ -164,6 +170,7 @@ const getXRayMiddleware = (config: RegionResolvedConfig, manualSegment?: Segment
164170
service,
165171
operation,
166172
await config.region(),
173+
commandInput,
167174
null,
168175
err,
169176
);

packages/core/test/unit/patchers/aws3_p.test.js

Lines changed: 84 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,38 @@ chai.use(sinonChai);
1818

1919
var traceId = '1-57fbe041-2c7ad569f5d6ff149137be86';
2020

21-
describe('AWS v3 patcher', function() {
22-
describe('#captureAWSClient', function() {
21+
describe('AWS v3 patcher', function () {
22+
describe('#captureAWSClient', function () {
2323
var sandbox, useMiddleware;
2424

2525
var awsClient = {
26-
send: function() {},
26+
send: function () { },
2727
config: {
2828
serviceId: 's3',
2929
},
3030
middlewareStack: constructStack(),
3131
};
3232

33-
beforeEach(function() {
33+
beforeEach(function () {
3434
sandbox = sinon.createSandbox();
3535
useMiddleware = sandbox.stub(awsClient.middlewareStack, 'use');
3636
});
3737

38-
afterEach(function() {
38+
afterEach(function () {
3939
sandbox.restore();
4040
});
4141

42-
it('should call middlewareStack.use and return the service', function() {
42+
it('should call middlewareStack.use and return the service', function () {
4343
const patched = awsPatcher.captureAWSClient(awsClient);
4444
useMiddleware.should.have.been.calledOnce;
4545
assert.equal(patched, awsClient);
4646
});
4747
});
4848

49-
describe('#captureAWSRequest', function() {
50-
var awsClient, awsRequest, sandbox, segment, stubResolve, addNewSubsegmentStub, sub;
49+
describe('#captureAWSRequest', function () {
50+
let awsClient, awsRequest, ddbClient, ddbGetRequest, sandbox, segment, stubResolve, addNewSubsegmentStub, sub;
5151

52-
before(function() {
52+
before(function () {
5353
awsClient = {
5454
send: async (req) => {
5555
const context = {
@@ -74,9 +74,34 @@ describe('AWS v3 patcher', function() {
7474
},
7575
middlewareStack: constructStack(),
7676
};
77+
78+
ddbClient = {
79+
send: async (req) => {
80+
const middlewareContext = {
81+
clientName: 'DynamoDBClient',
82+
commandName: 'GetItemCommand',
83+
};
84+
const handler = awsClient.middlewareStack.resolve((args) => {
85+
const error = req.response.error;
86+
if (error) {
87+
const err = new Error(error.message);
88+
err.name = error.code;
89+
err.$metadata = req.response.$metadata;
90+
throw err;
91+
}
92+
return args;
93+
}, middlewareContext);
94+
await handler(req);
95+
return req.response;
96+
},
97+
config: {
98+
region: async () => 'us-east-1',
99+
},
100+
middlewareStack: constructStack(),
101+
};
77102
});
78103

79-
beforeEach(function() {
104+
beforeEach(function () {
80105
sandbox = sinon.createSandbox();
81106

82107
awsRequest = new (class ListBucketsCommand {
@@ -99,14 +124,39 @@ describe('AWS v3 patcher', function() {
99124
}
100125
})();
101126

127+
ddbGetRequest = new (class GetItemCommand {
128+
constructor() {
129+
this.request = {
130+
method: 'GET',
131+
url: '/',
132+
connection: {
133+
remoteAddress: 'localhost'
134+
},
135+
headers: {},
136+
};
137+
this.input = {
138+
TableName: 'TestTableName',
139+
ConsistentRead: true,
140+
};
141+
this.response = {};
142+
this.output = {
143+
ConsumedCapacity: 10,
144+
$metadata: {
145+
requestId: '123',
146+
extendedRequestId: '456',
147+
},
148+
};
149+
}
150+
})();
151+
102152
segment = new Segment('testSegment', traceId);
103-
segment.additionalTraceData = {'Foo': 'bar'};
153+
segment.additionalTraceData = { 'Foo': 'bar' };
104154
sub = segment.addNewSubsegment('subseg');
105155
stubResolve = sandbox.stub(contextUtils, 'resolveSegment').returns(segment);
106156
addNewSubsegmentStub = sandbox.stub(segment, 'addNewSubsegment').returns(sub);
107157
});
108158

109-
afterEach(function() {
159+
afterEach(function () {
110160
sandbox.restore();
111161
});
112162

@@ -125,13 +175,13 @@ describe('AWS v3 patcher', function() {
125175

126176
awsClient.send(awsRequest);
127177

128-
setTimeout(function() {
178+
setTimeout(function () {
129179
logStub.should.have.been.calledOnce;
130180
done();
131181
}, 50);
132182
});
133183

134-
it('should inject the tracing headers', async function() {
184+
it('should inject the tracing headers', async function () {
135185
await awsClient.send(awsRequest);
136186
assert.isTrue(addNewSubsegmentStub.calledWith('S3'));
137187

@@ -140,7 +190,7 @@ describe('AWS v3 patcher', function() {
140190
assert.match(awsRequest.request.headers['X-Amzn-Trace-Id'], expected);
141191
});
142192

143-
it('should close on complete with no errors when code 200 is seen', async function() {
193+
it('should close on complete with no errors when code 200 is seen', async function () {
144194
const closeStub = sandbox.stub(sub, 'close').returns();
145195
sandbox.stub(sub, 'addAttribute').returns();
146196
sandbox.stub(Aws.prototype, 'init').returns();
@@ -154,7 +204,7 @@ describe('AWS v3 patcher', function() {
154204
closeStub.should.have.been.calledWithExactly();
155205
});
156206

157-
it('should mark the subsegment as throttled and error if code 429 is seen', async function() {
207+
it('should mark the subsegment as throttled and error if code 429 is seen', async function () {
158208
const throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns();
159209

160210
sandbox.stub(sub, 'addAttribute').returns();
@@ -171,7 +221,7 @@ describe('AWS v3 patcher', function() {
171221
assert.isTrue(sub.error);
172222
});
173223

174-
it('should mark the subsegment as throttled and error if code service.throttledError returns true, regardless of status code', async function() {
224+
it('should mark the subsegment as throttled and error if code service.throttledError returns true, regardless of status code', async function () {
175225
const throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns();
176226

177227
sandbox.stub(sub, 'addAttribute').returns();
@@ -188,7 +238,7 @@ describe('AWS v3 patcher', function() {
188238
assert.isTrue(sub.error);
189239
});
190240

191-
it('should capture an error on the response and mark exception as remote', async function() {
241+
it('should capture an error on the response and mark exception as remote', async function () {
192242
const closeStub = sandbox.stub(sub, 'close').returns();
193243
const getCauseStub = sandbox.stub(Utils, 'getCauseTypeFromHttpStatus').returns();
194244

@@ -205,7 +255,15 @@ describe('AWS v3 patcher', function() {
205255
await awsClient.send(awsRequest).catch(() => null);
206256

207257
getCauseStub.should.have.been.calledWithExactly(500);
208-
closeStub.should.have.been.calledWithExactly(sinon.match({ message: error.message, name: error.code}), true);
258+
closeStub.should.have.been.calledWithExactly(sinon.match({ message: error.message, name: error.code }), true);
259+
});
260+
261+
it('should pass params into aws subsegment', async function () {
262+
await ddbClient.send(ddbGetRequest);
263+
264+
assert.isTrue(addNewSubsegmentStub.calledWith('DynamoDB'));
265+
addNewSubsegmentStub.returnValues[0].should.have.property('aws');
266+
addNewSubsegmentStub.returnValues[0].aws.should.include({ consistent_read: true, table_name: 'TestTableName', consumed_capacity: 10 });
209267
});
210268
});
211269

@@ -220,7 +278,7 @@ describe('AWS v3 patcher', function() {
220278

221279
awsClient.send(awsRequest);
222280

223-
setTimeout(function() {
281+
setTimeout(function () {
224282
logStub.should.have.been.calledOnce;
225283
done();
226284
}, 50);
@@ -250,10 +308,10 @@ describe('AWS v3 patcher', function() {
250308
});
251309

252310

253-
describe('#captureAWSRequest-Unsampled', function() {
311+
describe('#captureAWSRequest-Unsampled', function () {
254312
var awsClient, awsRequest, sandbox, segment, stubResolve, addNewSubsegmentStub, sub, service, addNewServiceSubsegmentStub;
255313

256-
before(function() {
314+
before(function () {
257315
awsClient = {
258316
send: async (req) => {
259317
const context = {
@@ -280,7 +338,7 @@ describe('AWS v3 patcher', function() {
280338
};
281339
});
282340

283-
beforeEach(function() {
341+
beforeEach(function () {
284342
sandbox = sinon.createSandbox();
285343

286344
awsRequest = new (class ListBucketsCommand {
@@ -304,7 +362,7 @@ describe('AWS v3 patcher', function() {
304362
})();
305363

306364
segment = new Segment('testSegment', traceId);
307-
segment.additionalTraceData = {'Foo': 'bar'};
365+
segment.additionalTraceData = { 'Foo': 'bar' };
308366
sub = segment.addNewSubsegmentWithoutSampling('subseg');
309367
service = sub.addNewSubsegmentWithoutSampling('service');
310368

@@ -314,7 +372,7 @@ describe('AWS v3 patcher', function() {
314372

315373
});
316374

317-
afterEach(function() {
375+
afterEach(function () {
318376
sandbox.restore();
319377
});
320378

@@ -328,7 +386,7 @@ describe('AWS v3 patcher', function() {
328386
});
329387

330388

331-
it('should inject the tracing headers', async function() {
389+
it('should inject the tracing headers', async function () {
332390
await awsClient.send(awsRequest);
333391
assert.isTrue(addNewServiceSubsegmentStub.calledWith('S3'));
334392

0 commit comments

Comments
 (0)