///|
// Prefer a 32-byte platform entropy source. If the target cannot provide one,
// stretch the millisecond wall clock into the required seed size. The fallback
// is deterministic and non-cryptographic, but keeps unsupported environments
// functional.
fn make_seed(random_bytes : (Int) -> Bytes?, now : () -> UInt64) -> Bytes {
match random_bytes(32) {
Some(seed) if seed.length() == 32 => return seed
_ => ()
}
let t = now()
let constants : Array[UInt64] = [
0UL, 0x9e3779b97f4a7c15UL, 0x6c62272e07bb0142UL, 0x94d049bb133111ebUL,
]
let arr : Array[Byte] = Array::make(32, b'\x00')
for seg in 0..<4 {
let v = t ^ constants[seg]
for i in 0..<8 {
arr[seg * 8 + i] = (v >> ((7 - i) * 8)).to_byte()
}
}
Bytes::from_array(arr[:])
}
///|
let rng : @random.Rand = @random.Rand::chacha8(
seed=make_seed(@env.rand, @env.now),
)
///|
fn to_hex_16(val : UInt64) -> String {
val.to_string(radix=16).pad_start(16, '0')
}
///|
pub fn next_trace_id() -> String {
let mut hi = rng.uint64()
let mut lo = rng.uint64()
// OTLP forbids all-zero trace IDs (probability 2^-128, checked for correctness)
while hi == 0UL && lo == 0UL {
hi = rng.uint64()
lo = rng.uint64()
}
to_hex_16(hi) + to_hex_16(lo)
}
///|
pub fn next_span_id() -> String {
let mut id = rng.uint64()
// OTLP forbids all-zero span IDs (probability 2^-64, checked for correctness)
while id == 0UL {
id = rng.uint64()
}
to_hex_16(id)
}