Skip to content

Commit

Permalink
Faster trace id generation (open-telemetry#824)
Browse files Browse the repository at this point in the history
  • Loading branch information
dyladan authored Mar 3, 2020
1 parent 86ce078 commit 5a5b6b8
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 13 deletions.
34 changes: 24 additions & 10 deletions packages/opentelemetry-core/src/platform/browser/id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,38 @@ declare type WindowWithMsCrypto = Window & {
const cryptoLib = window.crypto || (window as WindowWithMsCrypto).msCrypto;

const SPAN_ID_BYTES = 8;
const spanBytesArray = new Uint8Array(SPAN_ID_BYTES);
const TRACE_ID_BYTES = 16;
const randomBytesArray = new Uint8Array(TRACE_ID_BYTES);

/** Returns a random 16-byte trace ID formatted as a 32-char hex string. */
export function randomTraceId(): string {
return randomSpanId() + randomSpanId();
cryptoLib.getRandomValues(randomBytesArray);
return toHex(randomBytesArray.slice(0, TRACE_ID_BYTES));
}

/** Returns a random 8-byte span ID formatted as a 16-char hex string. */
export function randomSpanId(): string {
let spanId = '';
cryptoLib.getRandomValues(spanBytesArray);
for (let i = 0; i < SPAN_ID_BYTES; i++) {
const hexStr = spanBytesArray[i].toString(16);
cryptoLib.getRandomValues(randomBytesArray);
return toHex(randomBytesArray.slice(0, SPAN_ID_BYTES));
}

// Zero pad bytes whose hex values are single digit.
if (hexStr.length === 1) spanId += '0';
/**
* Get the hex string representation of a byte array
*
* @param byteArray
*/
function toHex(byteArray: Uint8Array) {
const chars: number[] = new Array(byteArray.length * 2);
const alpha = 'a'.charCodeAt(0) - 10;
const digit = '0'.charCodeAt(0);

spanId += hexStr;
let p = 0;
for (let i = 0; i < byteArray.length; i++) {
let nibble = (byteArray[i] >>> 4) & 0xf;
chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit;
nibble = byteArray[i] & 0xf;
chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit;
}
return spanId;

return String.fromCharCode.apply(null, chars);
}
3 changes: 2 additions & 1 deletion packages/opentelemetry-core/src/platform/node/id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
import * as crypto from 'crypto';

const SPAN_ID_BYTES = 8;
const TRACE_ID_BYTES = 16;

/**
* Returns a random 16-byte trace ID formatted/encoded as a 32 lowercase hex
* characters corresponding to 128 bits.
*/
export function randomTraceId(): string {
return randomSpanId() + randomSpanId();
return crypto.randomBytes(TRACE_ID_BYTES).toString('hex');
}

/**
Expand Down
20 changes: 18 additions & 2 deletions packages/opentelemetry-core/test/platform/id.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,31 @@ import * as assert from 'assert';
import { randomSpanId, randomTraceId } from '../../src/platform';

describe('randomTraceId', () => {
it('returns different 32-char hex strings', () => {
it('returns 32 character hex strings', () => {
const traceId = randomTraceId();
assert.ok(traceId.match(/[a-f0-9]{32}/));
assert.ok(!traceId.match(/^0+$/));
});

it('returns different ids on each call', () => {
const traceId1 = randomTraceId();
const traceId2 = randomTraceId();

assert.notDeepStrictEqual(traceId1, traceId2);
});
});

describe('randomSpanId', () => {
it('returns different 16-char hex string', () => {
it('returns 16 character hex strings', () => {
const spanId = randomSpanId();
assert.ok(spanId.match(/[a-f0-9]{16}/));
assert.ok(!spanId.match(/^0+$/));
});

it('returns different ids on each call', () => {
const spanId1 = randomSpanId();
const spanId2 = randomSpanId();

assert.notDeepStrictEqual(spanId1, spanId2);
});
});

0 comments on commit 5a5b6b8

Please sign in to comment.