pub fn generate_trace_id(request_id: Option<&str>) -> [u8; 16] {
match request_id {
Some(id) if !id.is_empty() && id != "-" => {
let hash = blake3::hash(id.as_bytes());
let mut trace_id = [0u8; 16];
trace_id.copy_from_slice(&hash.as_bytes()[..16]);
trace_id
}
_ => *uuid::Uuid::new_v4().as_bytes(),
}
}
pub fn generate_span_id() -> [u8; 8] {
let mut span_id = [0u8; 8];
rand::fill(&mut span_id);
span_id
}
pub fn hex_encode(bytes: &[u8]) -> String {
const HEX: &[u8; 16] = b"0123456789abcdef";
let mut s = String::with_capacity(bytes.len() * 2);
for &b in bytes {
s.push(HEX[(b >> 4) as usize] as char);
s.push(HEX[(b & 0x0f) as usize] as char);
}
s
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deterministic_for_same_request_id() {
let id1 = generate_trace_id(Some("abc123"));
let id2 = generate_trace_id(Some("abc123"));
assert_eq!(id1, id2);
}
#[test]
fn different_request_ids_produce_different_trace_ids() {
let id1 = generate_trace_id(Some("abc123"));
let id2 = generate_trace_id(Some("xyz789"));
assert_ne!(id1, id2);
}
#[test]
fn none_produces_nonzero() {
let id = generate_trace_id(None);
assert_ne!(id, [0u8; 16]);
}
#[test]
fn dash_treated_as_none() {
let id1 = generate_trace_id(Some("-"));
let id2 = generate_trace_id(Some("-"));
assert_ne!(id1, id2);
}
#[test]
fn empty_string_treated_as_none() {
let id1 = generate_trace_id(Some(""));
let id2 = generate_trace_id(Some(""));
assert_ne!(id1, id2);
}
#[test]
fn span_id_is_nonzero() {
let id = generate_span_id();
assert_ne!(id, [0u8; 8]);
}
#[test]
fn span_ids_are_unique() {
let id1 = generate_span_id();
let id2 = generate_span_id();
assert_ne!(id1, id2);
}
#[test]
fn hex_encode_works() {
assert_eq!(hex_encode(&[0x0A, 0xFF, 0x00]), "0aff00");
assert_eq!(hex_encode(&[]), "");
}
}