diff --git a/packages/opentelemetry-core/src/platform/browser/id.ts b/packages/opentelemetry-core/src/platform/browser/id.ts index ab1c8188ac..02af4b220e 100644 --- a/packages/opentelemetry-core/src/platform/browser/id.ts +++ b/packages/opentelemetry-core/src/platform/browser/id.ts @@ -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); } diff --git a/packages/opentelemetry-core/src/platform/node/id.ts b/packages/opentelemetry-core/src/platform/node/id.ts index 75350e6eff..fa4cd6a916 100644 --- a/packages/opentelemetry-core/src/platform/node/id.ts +++ b/packages/opentelemetry-core/src/platform/node/id.ts @@ -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'); } /** diff --git a/packages/opentelemetry-core/test/platform/id.test.ts b/packages/opentelemetry-core/test/platform/id.test.ts index 4a7226d392..8c4b7d0dc4 100644 --- a/packages/opentelemetry-core/test/platform/id.test.ts +++ b/packages/opentelemetry-core/test/platform/id.test.ts @@ -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); }); });