-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8b325de
commit 1995e82
Showing
11 changed files
with
781 additions
and
136 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,3 +84,6 @@ packages/**/*.tgz | |
!.yarn/releases | ||
!.yarn/sdks | ||
!.yarn/versions | ||
|
||
# Jest | ||
coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
224 changes: 224 additions & 0 deletions
224
...es/core/src/rum/instrumentation/resourceTracking/distributedTracing/TracingIdentifier.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2016-Present Datadog, Inc. | ||
*/ | ||
|
||
/** | ||
* Available formats for representing the {@link TracingIdentifier} as a string. | ||
*/ | ||
export enum TracingIdFormat { | ||
/** | ||
* Decimal string representation of the full tracing id. | ||
*/ | ||
decimal, | ||
|
||
/** | ||
* The low bits of the tracing id as a decimal. | ||
*/ | ||
lowDecimal, | ||
|
||
/** | ||
* The high bits of the tracing id as a decimal. | ||
*/ | ||
highDecimal, | ||
|
||
/** | ||
* Hexadecimal string representation of the full tracing id. | ||
*/ | ||
hex, | ||
|
||
/** | ||
* Hexadecimal string representation of the low bits of the tracing id. | ||
*/ | ||
lowHex, | ||
|
||
/** | ||
* Hexadecimal string representation of the high bits of the tracing id. | ||
*/ | ||
highHex, | ||
|
||
/** | ||
* Padded hexadecimal string representation of the full tracing id. | ||
*/ | ||
paddedHex, | ||
|
||
/** | ||
* Padded hexadecimal string representation of the low bits of the tracing id. | ||
*/ | ||
paddedLowHex, | ||
|
||
/** | ||
* Padded hexadecimal string representation of the high bits of the tracing id. | ||
*/ | ||
paddedHighHex | ||
} | ||
|
||
/** | ||
* A {@link TracingIdentifier} used for Traces (128 bit). | ||
*/ | ||
export type TraceId = TracingIdentifier & { | ||
_brand: 'traceId'; | ||
}; | ||
|
||
/** | ||
* A {@link TracingIdentifier} used for Spans (64 bit). | ||
*/ | ||
export type SpanId = TracingIdentifier & { | ||
_brand: 'spanId'; | ||
}; | ||
|
||
/** | ||
* The tracing identifier type. | ||
*/ | ||
export type TracingIdentifierType = 'trace' | 'span'; | ||
|
||
/** | ||
* Value used to mask the low 64 bits of the trace identifier. | ||
*/ | ||
const LOW_64BIT_MASK = (BigInt('0xffffffff') << 32n) + BigInt('0xffffffff'); | ||
|
||
/** | ||
* Value used to mask the low 32 bits of the trace identifier. | ||
*/ | ||
const LOW_32BIT_MASK = (BigInt('0xffff') << 16n) + BigInt('0xffff'); | ||
|
||
/** | ||
* A {@link TracingIdentifier} is a unique UUID that can be 64bit or 128bit, and provides | ||
* convenient methods to represent it as a HEX or DECIMAL string, and it allows the masking | ||
* of its low or high bits. | ||
* | ||
* Create a new identifier by calling {@link TracingIdentifier.createTraceId()} or | ||
* {@link TracingIdentifier.createSpanId()}. | ||
*/ | ||
export class TracingIdentifier { | ||
/** | ||
* Read-only generated ID as a {@link bigint}. | ||
*/ | ||
readonly id: bigint; | ||
|
||
/** | ||
* Read-only type to determine whether the identifier is a {@link TraceId} or a {@link SpanId}. | ||
*/ | ||
readonly type: TracingIdentifierType; | ||
|
||
/** | ||
* Creates a new unique Trace ID. | ||
* @returns the generated {@link TraceId}. | ||
*/ | ||
public static createTraceId(): TraceId { | ||
return new TracingIdentifier('trace') as TraceId; | ||
} | ||
|
||
/** | ||
* Creates a new unique Span ID. | ||
* @returns the generated {@link SpanId}. | ||
*/ | ||
public static createSpanId(): SpanId { | ||
return new TracingIdentifier('span') as SpanId; | ||
} | ||
|
||
/** | ||
* Private constructor to initialize the {@link TracingIdentifier} based on the given | ||
* {@link TracingIdentifierType}. | ||
*/ | ||
private constructor(type: TracingIdentifierType) { | ||
switch (type) { | ||
case 'trace': | ||
this.id = this.generateUUID('128bit'); | ||
break; | ||
case 'span': | ||
this.id = this.generateUUID('64bit'); | ||
break; | ||
} | ||
|
||
this.type = type; | ||
} | ||
|
||
/** | ||
* Generates a unique ID with the given format. | ||
* @param format - the desired format (64bit or 128bit). | ||
* @returns the generated UUID as a {@link bigint}. | ||
*/ | ||
private generateUUID(format: '64bit' | '128bit'): bigint { | ||
// Get the current Unix timestamp in seconds | ||
const unixSeconds = Math.floor(Date.now() / 1000); | ||
|
||
// Ensure the Unix timestamp is 32 bits | ||
const unixSeconds32 = unixSeconds & 0xffffffff; | ||
|
||
// 32 bits of zero | ||
const zeros32 = 0; | ||
|
||
// Generate 64 random bits using Math.random() | ||
const random32Bit1 = Math.floor(Math.random() * 0xffffffff); | ||
const random32Bit2 = Math.floor(Math.random() * 0xffffffff); | ||
const random64Hex = | ||
random32Bit1.toString(16).padStart(8, '0') + | ||
random32Bit2.toString(16).padStart(8, '0'); | ||
|
||
// If format is 64bit we return it immediately | ||
if (format === '64bit') { | ||
return BigInt(`0x${random64Hex}`); | ||
} | ||
|
||
// Convert parts to hexadecimal strings | ||
const unixSecondsHex = unixSeconds32.toString(16).padStart(8, '0'); | ||
const zerosHex = zeros32.toString(16).padStart(8, '0'); | ||
|
||
// Combine parts to form the 128-bit ID | ||
const hex128BitID = unixSecondsHex + zerosHex + random64Hex; | ||
|
||
return BigInt(`0x${hex128BitID}`); | ||
} | ||
|
||
/** | ||
* Returns a string representation of the Tracing ID. | ||
* @param format - The type of representation to use. | ||
* @returns The ID as a string in the specified representation type. | ||
*/ | ||
public toString(format: TracingIdFormat): string { | ||
const lowTraceMask = | ||
this.type === 'trace' ? LOW_64BIT_MASK : LOW_32BIT_MASK; | ||
const highTraceMask = this.type === 'trace' ? 64n : 32n; | ||
const padding = this.type === 'trace' ? 32 : 16; | ||
|
||
switch (format) { | ||
case TracingIdFormat.decimal: | ||
return this.id.toString(10); | ||
|
||
case TracingIdFormat.lowDecimal: | ||
return (this.id & lowTraceMask).toString(10); | ||
|
||
case TracingIdFormat.highDecimal: | ||
return (this.id >> highTraceMask).toString(10); | ||
|
||
case TracingIdFormat.hex: | ||
return this.id.toString(16); | ||
|
||
case TracingIdFormat.lowHex: | ||
return (this.id & lowTraceMask).toString(16); | ||
|
||
case TracingIdFormat.highHex: | ||
return (this.id >> highTraceMask).toString(16); | ||
|
||
case TracingIdFormat.paddedHex: | ||
return this.toString(TracingIdFormat.hex).padStart( | ||
padding, | ||
'0' | ||
); | ||
|
||
case TracingIdFormat.paddedLowHex: | ||
return this.toString(TracingIdFormat.lowHex).padStart( | ||
padding / 2, | ||
'0' | ||
); | ||
|
||
case TracingIdFormat.paddedHighHex: | ||
return this.toString(TracingIdFormat.highHex).padStart( | ||
padding / 2, | ||
'0' | ||
); | ||
} | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
...ntation/resourceTracking/distributedTracing/__tests__/__utils__/TracingIdentifierUtils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2016-Present Datadog, Inc. | ||
*/ | ||
|
||
export default class TracingIdentifierUtils { | ||
/** | ||
* Extracts the Unix timestamp from the 128-bit hex string representation. | ||
* @param idHex - The 128-bit ID as a hexadecimal string. | ||
* @returns The Unix timestamp as a number. | ||
*/ | ||
public static extractTimestamp(idHex: string): number { | ||
// Extract the first 8 characters which represent the 32-bit Unix timestamp | ||
const timestampHex = idHex.substring(0, 8); | ||
|
||
// Convert the hexadecimal string to a number | ||
const timestamp = parseInt(timestampHex, 16); | ||
|
||
return timestamp; | ||
} | ||
|
||
/** | ||
* Checks if a string representation of an ID in a given radix is within 32 bits. | ||
* @param idString - The string representation of the ID. | ||
* @param radix - Optional base to use for the conversion (default is 10). | ||
* @returns True if the ID is within 32 bits, otherwise false. | ||
*/ | ||
public static isWithin32Bits( | ||
idString: string, | ||
radix: number = 10 | ||
): boolean { | ||
const bigIntValue = BigInt(parseInt(idString, radix)); | ||
return bigIntValue < BigInt(1) << BigInt(32); | ||
} | ||
|
||
/** | ||
* Checks if a string representation of an ID in a given radix is within 64 bits. | ||
* @param idString - The string representation of the ID. | ||
* @param radix - Optional base to use for the conversion (default is 10). | ||
* @returns True if the ID is within 64 bits, otherwise false. | ||
*/ | ||
public static isWithin64Bits( | ||
idString: string, | ||
radix: number = 10 | ||
): boolean { | ||
const bigIntValue = BigInt(parseInt(idString, radix)); | ||
return bigIntValue < BigInt(1) << BigInt(64); | ||
} | ||
|
||
/** | ||
* Checks if a string representation of an ID in a given radix is within 128 bits. | ||
* @param idString - The string representation of the ID. | ||
* @param radix - Optional base to use for the conversion (default is 10). | ||
* @returns True if the ID is within 128 bits, otherwise false. | ||
*/ | ||
public static isWithin128Bits( | ||
idString: string, | ||
radix: number = 10 | ||
): boolean { | ||
const bigIntValue = BigInt(parseInt(idString, radix)); | ||
return bigIntValue < BigInt(1) << BigInt(128); | ||
} | ||
} |
Oops, something went wrong.