Skip to content

Commit 053b90f

Browse files
authored
Merge pull request #657 from wangzlei/master
Revert #651 [Lambda] Replace Facade with No-Op if trace header is missing data
2 parents 23ff8bb + 71b6f2c commit 053b90f

File tree

10 files changed

+24
-224
lines changed

10 files changed

+24
-224
lines changed

packages/core/lib/context_utils.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,8 @@ var contextUtils = {
9999

100100
if (!segment) {
101101
contextUtils.contextMissingStrategy.contextMissing('Failed to get the current sub/segment from the context.');
102-
} else if (segment instanceof Segment && process.env.LAMBDA_TASK_ROOT) {
103-
if (segment.facade == true || segment.noOp == true) {
104-
segment.resolveLambdaTraceData();
105-
}
102+
} else if (segment instanceof Segment && process.env.LAMBDA_TASK_ROOT && segment.facade == true) {
103+
segment.resolveLambdaTraceData();
106104
}
107105

108106
return segment;

packages/core/lib/env/aws_lambda.js

+1-78
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,7 @@ module.exports.init = function init() {
3636

3737
var namespace = contextUtils.getNamespace();
3838
namespace.enter(namespace.createContext());
39-
40-
if (LambdaUtils.validTraceData(process.env._X_AMZN_TRACE_ID)) {
41-
contextUtils.setSegment(facadeSegment());
42-
} else {
43-
contextUtils.setSegment(noOpSegment());
44-
}
39+
contextUtils.setSegment(facadeSegment());
4540
};
4641

4742
var facadeSegment = function facadeSegment() {
@@ -114,75 +109,3 @@ var facadeSegment = function facadeSegment() {
114109

115110
return segment;
116111
};
117-
118-
var noOpSegment = function noOpSegment() {
119-
var segment = new Segment('no-op');
120-
var whitelistFcn = [];
121-
var silentFcn = ['addNewSubsegment', 'addSubsegment', 'removeSubsegment', 'toString', 'addSubsegmentWithoutSampling', 'addNewSubsegmentWithoutSampling', 'incrementCounter', 'decrementCounter', 'isClosed', 'close', 'format', 'flush'];
122-
var xAmznTraceId = process.env._X_AMZN_TRACE_ID;
123-
124-
for (var key in segment) {
125-
if (typeof segment[key] === 'function' && whitelistFcn.indexOf(key) === -1) {
126-
if (silentFcn.indexOf(key) === -1) {
127-
segment[key] = (function() {
128-
var func = key;
129-
return function noOp() {
130-
logger.getLogger().warn('Function "' + func + '" cannot be called on an AWS Lambda segment. Please use a subsegment to record data.');
131-
return;
132-
};
133-
})();
134-
} else {
135-
segment[key] = function noOp() {
136-
return;
137-
};
138-
}
139-
}
140-
}
141-
142-
segment.trace_id = TraceID.Invalid().toString();
143-
segment.isClosed = function() {
144-
return true;
145-
};
146-
segment.in_progress = false;
147-
segment.counter = 1;
148-
segment.notTraced = true;
149-
segment.noOp = true;
150-
151-
segment.reset = function reset() {
152-
this.trace_id = TraceID.Invalid().toString();
153-
this.id = '00000000';
154-
delete this.subsegments;
155-
this.notTraced = true;
156-
};
157-
158-
segment.resolveLambdaTraceData = function resolveLambdaTraceData() {
159-
var xAmznLambda = process.env._X_AMZN_TRACE_ID;
160-
161-
if (xAmznLambda) {
162-
163-
// This check resets the trace data whenever a new trace header is read to not leak data between invocations
164-
if (xAmznLambda != xAmznTraceIdPrev) {
165-
this.reset();
166-
167-
if (LambdaUtils.populateTraceData(segment, xAmznLambda)) {
168-
xAmznTraceIdPrev = xAmznLambda;
169-
}
170-
}
171-
} else {
172-
this.reset();
173-
contextUtils.contextMissingStrategy.contextMissing('Missing AWS Lambda trace data for X-Ray. ' +
174-
'Ensure Active Tracing is enabled and no subsegments are created outside the function handler.');
175-
}
176-
};
177-
178-
// Since we're in a no-op segment, do not check if the trace data is valid; simply propagate the information
179-
if (LambdaUtils.populateTraceData(segment, xAmznTraceId)) {
180-
xAmznTraceIdPrev = xAmznTraceId;
181-
}
182-
183-
return segment;
184-
};
185-
186-
// For testing
187-
export const exportedFacadeSegment = { facadeSegment };
188-
export const exportedNoOpSegment = { noOpSegment };

packages/core/lib/patchers/aws3_p.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,14 @@ const getXRayMiddleware = (config: RegionResolvedConfig, manualSegment?: Segment
125125
const parent = (segment instanceof Subsegment ? segment.segment : segment);
126126
const data = parent.segment ? parent.segment.additionalTraceData : parent.additionalTraceData;
127127

128-
let traceHeader = 'Root=' + parent.trace_id;
129-
if (!(parent && parent.noOp)) {
130-
traceHeader += ';Parent=' + subsegment.id + ';Sampled=' + (subsegment.notTraced ? '0' : '1');
131-
}
128+
let traceHeader = stringify(
129+
{
130+
Root: parent.trace_id,
131+
Parent: subsegment.id,
132+
Sampled: subsegment.notTraced ? '0' : '1',
133+
},
134+
';',
135+
);
132136

133137
if (data != null) {
134138
for (const [key, value] of Object.entries(data)) {

packages/core/lib/patchers/aws_p.js

+2-8
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,8 @@ function captureAWSRequest(req) {
8888
const data = parent.segment ? parent.segment.additionalTraceData : parent.additionalTraceData;
8989

9090
var buildListener = function(req) {
91-
let traceHeader = 'Root=' + traceId;
92-
// Only append parent and sample if not in Lambda PassThrough mode
93-
if (!(parent && parent.noOp)) {
94-
traceHeader += ';Parent=' + subsegment.id + ';Sampled=' + (subsegment.notTraced ? '0' : '1');
95-
}
91+
let traceHeader = 'Root=' + traceId + ';Parent=' + subsegment.id +
92+
';Sampled=' + (subsegment.notTraced ? '0' : '1');
9693
if (data != null) {
9794
for (const [key, value] of Object.entries(data)) {
9895
traceHeader += ';' + key +'=' + value;
@@ -102,9 +99,6 @@ function captureAWSRequest(req) {
10299
};
103100

104101
var completeListener = function(res) {
105-
if (subsegment == null) {
106-
return;
107-
}
108102
subsegment.addAttribute('namespace', 'aws');
109103
subsegment.addAttribute('aws', new Aws(res, subsegment.name));
110104

packages/core/lib/patchers/http_p.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -123,18 +123,15 @@ function enableCapture(module, downstreamXRayEnabled, subsegmentCallback) {
123123
subsegment = parent.addNewSubsegment(hostname);
124124
}
125125

126+
const root = parent.segment ? parent.segment : parent;
126127
subsegment.namespace = 'remote';
127128

128129
if (!options.headers) {
129130
options.headers = {};
130131
}
131132

132-
let traceHeader = 'Root=' + (parent.segment ? parent.segment : parent).trace_id;
133-
if (!(parent && parent.noOp)) {
134-
traceHeader += ';Parent=' + subsegment.id + ';Sampled=' + (subsegment.notTraced ? '0' : '1');
135-
}
136-
137-
options.headers['X-Amzn-Trace-Id'] = traceHeader;
133+
options.headers['X-Amzn-Trace-Id'] = 'Root=' + root.trace_id + ';Parent=' + subsegment.id +
134+
';Sampled=' + (subsegment.notTraced ? '0' : '1');
138135

139136
const errorCapturer = function errorCapturer(e) {
140137
if (subsegmentCallback) {

packages/core/lib/utils.js

-2
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,6 @@ var utils = {
168168
if (!traceData) {
169169
traceData = {};
170170
logger.getLogger().error('_X_AMZN_TRACE_ID is empty or has an invalid format');
171-
} else if (segment.noOp == true && traceData.root) {
172-
valid = true;
173171
} else if (!traceData.root || !traceData.parent || !traceData.sampled) {
174172
logger.getLogger().error('_X_AMZN_TRACE_ID is missing required information');
175173
} else {

packages/core/test/unit/env/aws_lambda.test.js

+4-12
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ describe('AWSLambda', function() {
8181
assert.equal(facade.trace_id, TraceID.Invalid().toString());
8282
});
8383

84-
describe('the facade/no-op segment', function() {
84+
describe('the facade segment', function() {
8585
afterEach(function() {
8686
populateStub.returns(true);
8787
delete process.env._X_AMZN_TRACE_ID;
@@ -95,25 +95,17 @@ describe('AWSLambda', function() {
9595
validateStub.should.have.been.calledWith(process.env._X_AMZN_TRACE_ID);
9696
});
9797

98-
it('should call populateTraceData on Facade if validTraceData returns true', function() {
98+
it('should call populateTraceData if validTraceData returns true', function() {
9999
Lambda.init();
100100

101-
var segment = setSegmentStub.args[0][0];
102-
assert.equal(segment.name, 'facade');
103-
assert.isTrue(segment.facade);
104-
105101
populateStub.should.have.been.calledOnce;
106102
});
107103

108-
it('should call populateTraceData on No-Op if validTraceData returns false', function() {
104+
it('should not call populateTraceData if validTraceData returns false', function() {
109105
validateStub.returns(false);
110106
Lambda.init();
111107

112-
var segment = setSegmentStub.args[0][0];
113-
assert.equal(segment.name, 'no-op');
114-
assert.isTrue(segment.noOp);
115-
116-
populateStub.should.have.been.calledOnce;
108+
populateStub.should.have.not.been.called;
117109
});
118110
});
119111
});

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

-91
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ var Utils = require('../../../lib/utils');
1313

1414
var logger = require('../../../lib/logger').getLogger();
1515

16-
import { exportedFacadeSegment, exportedNoOpSegment } from '../../../lib/env/aws_lambda';
17-
const { facadeSegment } = exportedFacadeSegment;
18-
const { noOpSegment } = exportedNoOpSegment;
19-
2016
chai.should();
2117
chai.use(sinonChai);
2218

@@ -352,91 +348,4 @@ describe('AWS patcher', function() {
352348
});
353349

354350
});
355-
356-
357-
describe('#captureAWSRequest-Lambda-PassThrough', function() {
358-
var awsClient, awsRequest, MyEmitter, sandbox, segment, stubResolve, tempHeader;
359-
360-
before(function() {
361-
MyEmitter = function() {
362-
EventEmitter.call(this);
363-
};
364-
365-
awsClient = {
366-
customizeRequests: function customizeRequests(captureAWSRequest) {
367-
this.call = captureAWSRequest;
368-
},
369-
throttledError: function throttledError() {}
370-
};
371-
awsClient = awsPatcher.captureAWSClient(awsClient);
372-
373-
util.inherits(MyEmitter, EventEmitter);
374-
});
375-
376-
beforeEach(function() {
377-
sandbox = sinon.createSandbox();
378-
379-
awsRequest = {
380-
httpRequest: {
381-
method: 'GET',
382-
url: '/',
383-
connection: {
384-
remoteAddress: 'localhost'
385-
},
386-
headers: {}
387-
},
388-
response: {}
389-
};
390-
391-
awsRequest.on = function(event, fcn) {
392-
if (event === 'complete') {
393-
this.emitter.on(event, fcn.bind(this, this.response));
394-
} else {
395-
this.emitter.on(event, fcn.bind(this, this));
396-
}
397-
return this;
398-
};
399-
400-
awsRequest.emitter = new MyEmitter();
401-
402-
tempHeader = process.env._X_AMZN_TRACE_ID;
403-
process.env._X_AMZN_TRACE_ID = 'Root=' + traceId + ';Foo=bar';
404-
405-
segment = noOpSegment();
406-
407-
stubResolve = sandbox.stub(contextUtils, 'resolveSegment').returns(segment);
408-
});
409-
410-
afterEach(function() {
411-
process.env._X_AMZN_TRACE_ID = tempHeader;
412-
sandbox.restore();
413-
});
414-
415-
it('should log an info statement and exit if parent is not found on the context or on the call params', function(done) {
416-
stubResolve.returns();
417-
var logStub = sandbox.stub(logger, 'info');
418-
419-
awsClient.call(awsRequest);
420-
421-
setTimeout(function() {
422-
logStub.should.have.been.calledOnce;
423-
done();
424-
}, 50);
425-
});
426-
427-
it('should inject the tracing headers', function(done) {
428-
sandbox.stub(contextUtils, 'isAutomaticMode').returns(true);
429-
430-
awsClient.call(awsRequest);
431-
432-
awsRequest.emitter.emit('build');
433-
434-
setTimeout(function() {
435-
var expected = new RegExp('^Root=' + traceId + ';Foo=bar$');
436-
assert.match(awsRequest.httpRequest.headers['X-Amzn-Trace-Id'], expected);
437-
done();
438-
}, 50);
439-
});
440-
441-
});
442351
});

sdk_contrib/fetch/lib/fetch_p.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,10 @@ const enableCapture = function enableCapture(baseFetchFunction, requestClass, do
104104

105105
subsegment.namespace = 'remote';
106106

107-
let traceHeader = 'Root=' + (parent.segment ? parent.segment : parent).trace_id;
108-
if (!(parent && parent.noOp)) {
109-
traceHeader += ';Parent=' + subsegment.id + ';Sampled=' + (subsegment.notTraced ? '0' : '1');
110-
}
111-
112-
request.headers.set('X-Amzn-Trace-Id', traceHeader);
107+
request.headers.set('X-Amzn-Trace-Id',
108+
'Root=' + (parent.segment ? parent.segment : parent).trace_id +
109+
';Parent=' + subsegment.id +
110+
';Sampled=' + (subsegment.notTraced ? '0' : '1'));
113111

114112
// Set up fetch call and capture any thrown errors
115113
const capturedFetch = async () => {

sdk_contrib/fetch/test/unit/fetch_p.test.js

-13
Original file line numberDiff line numberDiff line change
@@ -273,19 +273,6 @@ describe('Unit tests', function () {
273273
'Root=12345;Parent=999;Sampled=1');
274274
});
275275

276-
it('adds X-Amzn-Trace-Id header with only root if noOp', async function () {
277-
const activeFetch = captureFetch(true);
278-
stubParentSegment.noOp = true;
279-
stubParentSegment.trace_id = '12345';
280-
stubSubsegment.notTraced = false;
281-
stubSubsegment.id = '999';
282-
const request = new FetchRequest('https://www.foo.com/test');
283-
const requestHeadersSet = sandbox.stub(request.headers, 'set');
284-
await activeFetch(request);
285-
requestHeadersSet.should.have.been.calledOnceWith('X-Amzn-Trace-Id',
286-
'Root=12345');
287-
});
288-
289276
it('calls subsegmentCallback on successful response', async function () {
290277
const spyCallback = sandbox.spy();
291278
const activeFetch = captureFetch(true, spyCallback);

0 commit comments

Comments
 (0)