use opentelemetry::trace::{SpanId, TraceId};
use opentelemetry_sdk::trace::{IdGenerator, RandomIdGenerator};
use std::time::{Duration, UNIX_EPOCH};
#[derive(Debug, Default)]
pub struct XrayIdGenerator {
sdk_default_generator: RandomIdGenerator,
}
impl IdGenerator for XrayIdGenerator {
fn new_trace_id(&self) -> TraceId {
let mut default_trace_id: String =
format!("{:024x}", self.sdk_default_generator.new_trace_id());
default_trace_id.truncate(24);
let epoch_time_seconds: u64 = opentelemetry::time::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_else(|_| Duration::from_secs(0))
.as_secs();
TraceId::from_hex(format!("{epoch_time_seconds:08x}{default_trace_id}").as_str())
.unwrap_or(TraceId::INVALID)
}
fn new_span_id(&self) -> SpanId {
self.sdk_default_generator.new_span_id()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread::sleep;
#[test]
fn test_trace_id_generation() {
let before: u64 = opentelemetry::time::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
sleep(Duration::from_secs(1));
let generator: XrayIdGenerator = XrayIdGenerator::default();
let trace_id: TraceId = generator.new_trace_id();
sleep(Duration::from_secs(1));
let after: u64 = opentelemetry::time::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let trace_as_hex = trace_id.to_string();
let (timestamp, _xray_id) = trace_as_hex.split_at(8_usize);
let trace_time: u64 = u64::from_str_radix(timestamp, 16).unwrap();
assert!(before <= trace_time);
assert!(after >= trace_time);
}
}