Skip to content
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

Change span ID to use random bytes #654

Merged
merged 12 commits into from
Jan 20, 2018
14 changes: 10 additions & 4 deletions src/span-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,15 @@ interface StackFrame {
column_number?: number;
}

// Auto-incrementing integer
let uid = 1;
// Span IDs in the X-Cloud-Trace-Context header are 64-bit unsigned integers
// This is the largest JavaScript number that is less than the max unsigned
// 64-bit int, that is less than 2^64-1.
const SPAN_ID_MAX = 18446744073709550000;

function randomSpanId() {
// No rounding is needed because SPAN_ID_MAX is bigger than 1 / Number.EPSILON
return String(Math.random() * SPAN_ID_MAX);

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

}

export class SpanData implements SpanDataInterface {
readonly span: TraceSpan;
Expand All @@ -60,10 +67,9 @@ export class SpanData implements SpanDataInterface {
constructor(
readonly trace: Trace, spanName: string, parentSpanId: string,
private readonly isRoot: boolean, skipFrames: number) {
const spanId = '' + (uid++);
spanName =
traceUtil.truncate(spanName, Constants.TRACE_SERVICE_SPAN_NAME_LIMIT);
this.span = new TraceSpan(spanName, spanId, parentSpanId);
this.span = new TraceSpan(spanName, randomSpanId(), parentSpanId);
trace.spans.push(this.span);
if (traceWriter.get().getConfig().stackTraceLimit > 0) {
// This is a mechanism to get the structured stack trace out of V8.
Expand Down
20 changes: 20 additions & 0 deletions test/test-span-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,26 @@ describe('SpanData', function() {
});
});

it('generates unique numeric span ID strings', function() {
cls.getNamespace().run(function() {
var spans = [];
var spanIds = new Set<string>();
var rootSpanData = createRootSpanData('hi');
var numSpanIdsToCheck = 5;
for (var i = 0; i < numSpanIdsToCheck; i++) {
var spanData = new SpanData(
rootSpanData.trace, 'child', rootSpanData.span.spanId, false, 0);
var spanId = spanData.span.spanId;
spanIds.add(spanId);
// Check that the span IDs are numeric positive number strings
assert.ok(typeof spanId === 'string');
assert.ok(spanId.match(/\d+/));
assert.ok(Number(spanId) > 0);
assert.strictEqual(Number(spanId).toString(), spanId);
}
});
});

it('converts label values to strings', function() {
cls.getNamespace().run(function() {
var spanData = createRootSpanData('name', 1, 2);
Expand Down
44 changes: 27 additions & 17 deletions test/test-trace-header-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,34 +101,44 @@ describe('test-trace-header-context', function() {
it('should parse incoming header', function(done) {
var app = express();
var server;
var context = '123456/2;o=1';
app.get('/', function (req, res) {
http.get({ port: common.serverPort, path: '/self'});
var sentTraceId = '0000000000000000000000000000000a';
var sentSpanId = '2';
var sentTraceOptions = 'o=1';
var sentTraceContext = `${sentTraceId}/${sentSpanId};${sentTraceOptions}`;
app.get('/', function(req, res) {
http.get({port: common.serverPort, path: '/self'});
res.send(common.serverRes);
});
app.get('/self', function(req, res) {
assert.equal(
req.headers[Constants.TRACE_CONTEXT_HEADER_NAME].slice(0, 6),
context.slice(0, 6));
assert.equal(
req.headers[Constants.TRACE_CONTEXT_HEADER_NAME].slice(8),
';o=1');
var receivedTraceContext =
req.headers[Constants.TRACE_CONTEXT_HEADER_NAME];
var receivedTraceId = receivedTraceContext.split('/')[0];
var receivedSpanIdAndOptions =
receivedTraceContext.split('/')[1].split(';');
var receivedSpanId = receivedSpanIdAndOptions[0];
var receivedTraceOptions = receivedSpanIdAndOptions[1];
// Trace ID and trace options should be the same in sender and receiver.
assert.strictEqual(receivedTraceId, sentTraceId);
assert.strictEqual(receivedTraceOptions, sentTraceOptions);
// Span ID should be different as receiver generates a new span ID.
assert.notStrictEqual(receivedSpanId, sentSpanId);

res.send(common.serverRes);
var traces = common.getTraces();
assert.equal(traces.length, 2);
assert.equal(traces[0].spans.length, 2);
assert.equal(traces[1].spans.length, 1);
assert.equal(traces[0].spans[0].name, '/');
assert.equal(traces[0].spans[1].name, 'localhost');
assert.equal(traces[1].spans[0].name, '/self');
assert.strictEqual(traces.length, 2);
assert.strictEqual(traces[0].spans.length, 2);
assert.strictEqual(traces[1].spans.length, 1);
assert.strictEqual(traces[0].spans[0].name, '/');
assert.strictEqual(traces[0].spans[1].name, 'localhost');
assert.strictEqual(traces[1].spans[0].name, '/self');
common.cleanTraces();
server.close();
done();
});
server = app.listen(common.serverPort, function() {
var headers = {};
headers[Constants.TRACE_CONTEXT_HEADER_NAME] = context;
http.get({ port: common.serverPort, headers: headers });
headers[Constants.TRACE_CONTEXT_HEADER_NAME] = sentTraceContext;
http.get({port: common.serverPort, headers: headers});
});
});
});
Expand Down