// Copyright (c) 2026 Yingjie Shang
// agent-telemetry is licensed under Mulan PSL v2.
///|
/// Per-process counter to keep seeds unique even if called multiple times.
let seed_counter : Ref[Int] = Ref(0)
///|
/// Build a 32-byte seed from the current timestamp and a process counter.
///
/// The SDK's default RandomIdGenerator uses a fixed ChaCha8 seed, which causes
/// duplicate trace/span IDs across process restarts. Mixing in the current
/// nanosecond timestamp and a per-process counter ensures every process
/// produces unique IDs.
async fn make_seed() -> Bytes {
let (code, stdout, _stderr) = @process.collect_output("date", ["+%s%N"])
let timestamp = if code == 0 { stdout.text().trim().to_owned() } else { "0" }
let counter = seed_counter.val
seed_counter.val = seed_counter.val + 1
let text = "seed-" +
counter.to_string() +
"-" +
timestamp +
"-abcdefghijklmnopqrstuvwx"
// Take exactly 32 bytes; pad with '0' if shorter.
let mut padded = ""
for i = 0; i < 32; i = i + 1 {
if i < text.length() {
padded = padded + text[i:i + 1].to_owned()
} else {
padded = padded + "0"
}
}
let bytes : Array[Byte] = []
for ch in padded {
bytes.push(ch.to_int().to_byte())
}
Bytes::from_iter(bytes.iter())
}
///|
/// Create an IdGenerator with a process-unique seed.
///
/// This helper works around the SDK default RandomIdGenerator's fixed ChaCha8
/// seed, which produces duplicate trace/span IDs across process restarts.
pub async fn make_random_id_generator() -> @sdktrace.IdGenerator {
let seed = make_seed()
let random = @random.Rand::chacha8(seed~)
@sdktrace.IdGenerator::new(
fn() {
match @common.TraceId::from_hex(random_hex_32(random)) {
Some(id) => id
None => @common.TraceId::invalid()
}
},
fn() {
match @common.SpanId::from_hex(random_hex_16(random)) {
Some(id) => id
None => @common.SpanId::invalid()
}
},
)
}
///|
/// Generate a 32-character hex string (16 bytes).
fn random_hex_32(random : @random.Rand) -> String {
random_hex_16(random) + random_hex_16(random)
}
///|
/// Generate a 16-character hex string (8 bytes).
fn random_hex_16(random : @random.Rand) -> String {
random.uint64().to_string(radix=16).pad_start(16, '0')
}