Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,36 @@
*/
import { IdGenerator } from '../../trace/IdGenerator';

type WindowWithMsCrypto = Window & {
msCrypto?: Crypto;
};
const cryptoLib = window.crypto || (window as WindowWithMsCrypto).msCrypto;
const SPAN_ID_BYTES = 8;
const TRACE_ID_BYTES = 16;
const randomBytesArray = new Uint8Array(TRACE_ID_BYTES);

export class RandomIdGenerator implements IdGenerator {
/**
* Returns a random 16-byte trace ID formatted/encoded as a 32 lowercase hex
* characters corresponding to 128 bits.
*/
generateTraceId(): string {
cryptoLib.getRandomValues(randomBytesArray);
return this.toHex(randomBytesArray.slice(0, TRACE_ID_BYTES));
}
generateTraceId = getIdGenerator(TRACE_ID_BYTES);

/**
* Returns a random 8-byte span ID formatted/encoded as a 16 lowercase hex
* characters corresponding to 64 bits.
*/
generateSpanId(): string {
cryptoLib.getRandomValues(randomBytesArray);
return this.toHex(randomBytesArray.slice(0, SPAN_ID_BYTES));
}

/**
* Get the hex string representation of a byte array
*
* @param byteArray
*/
private toHex(byteArray: Uint8Array) {
const chars: number[] = new Array(byteArray.length * 2);
const alpha = 'a'.charCodeAt(0) - 10;
const digit = '0'.charCodeAt(0);
generateSpanId = getIdGenerator(SPAN_ID_BYTES);
}

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;
const SHARED_CHAR_CODES_ARRAY = Array(32);
function getIdGenerator(bytes: number): () => string {
return function generateId() {
for (let i = 0; i < bytes * 2; i++) {
SHARED_CHAR_CODES_ARRAY[i] = Math.floor(Math.random() * 16) + 48;
// valid hex characters in the range 48-57 and 97-102
if (SHARED_CHAR_CODES_ARRAY[i] >= 58) {
SHARED_CHAR_CODES_ARRAY[i] += 39;
}
}
return String.fromCharCode.apply(null, chars);
}
return String.fromCharCode.apply(
null,
SHARED_CHAR_CODES_ARRAY.slice(0, bytes * 2)
);
};
}
32 changes: 24 additions & 8 deletions packages/opentelemetry-core/src/platform/node/RandomIdGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
* limitations under the License.
*/

import * as crypto from 'crypto';
import { IdGenerator } from '../../trace/IdGenerator';

const SPAN_ID_BYTES = 8;
const TRACE_ID_BYTES = 16;

Expand All @@ -25,15 +23,33 @@ export class RandomIdGenerator implements IdGenerator {
* Returns a random 16-byte trace ID formatted/encoded as a 32 lowercase hex
* characters corresponding to 128 bits.
*/
generateTraceId(): string {
return crypto.randomBytes(TRACE_ID_BYTES).toString('hex');
}
generateTraceId = getIdGenerator(TRACE_ID_BYTES);

/**
* Returns a random 8-byte span ID formatted/encoded as a 16 lowercase hex
* characters corresponding to 64 bits.
*/
generateSpanId(): string {
return crypto.randomBytes(SPAN_ID_BYTES).toString('hex');
}
generateSpanId = getIdGenerator(SPAN_ID_BYTES);
}

const SHARED_BUFFER = Buffer.allocUnsafe(TRACE_ID_BYTES);
function getIdGenerator(bytes: number): () => string {
return function generateId() {
for (let i = 0; i < bytes / 4; i++) {
// unsigned right shift drops decimal part of the number
// it is required because if a number between 2**32 and 2**32 - 1 is generated, an out of range error is thrown by writeUInt32BE
SHARED_BUFFER.writeUInt32BE((Math.random() * 2 ** 32) >>> 0, i * 4);
}

// If buffer is all 0, set the last byte to 1 to guarantee a valid w3c id is generated
for (let i = 0; i < bytes; i++) {
if (SHARED_BUFFER[i] > 0) {
break;
} else if (i === bytes - 1) {
SHARED_BUFFER[bytes - 1] = 1;
}
}

return SHARED_BUFFER.toString('hex', 0, bytes);
};
}