use std::fmt;
use std::hash::{Hash, Hasher};
use std::thread::ThreadId;
use std::cell::Cell;
use tracing::Subscriber;
use tracing::span::{Attributes, Id};
use tracing_subscriber::{layer::Context, Layer};
use tracing_subscriber::registry::{LookupSpan, SpanRef};
pub struct RequestIdLayer;
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RequestId(u128);
#[derive(Default)]
pub struct IdentHasher(u128);
impl RequestId {
fn new() -> Self {
thread_local! {
pub static COUNTER: Cell<u64> = Cell::new(0);
pub static THREAD_ID: Cell<Option<ThreadId>> = Cell::new(None);
}
let thread_id = THREAD_ID.get().unwrap_or_else(|| {
let id = std::thread::current().id();
THREAD_ID.set(Some(id));
id
});
let local_id = COUNTER.get();
COUNTER.set(local_id.wrapping_add(1));
let mut hasher = IdentHasher::default();
thread_id.hash(&mut hasher);
local_id.hash(&mut hasher);
RequestId(hasher.0)
}
pub fn of<R: for<'a> LookupSpan<'a>>(span: &SpanRef<'_, R>) -> Option<Self> {
span.extensions().get::<Self>().copied()
}
pub fn current() -> Option<Self> {
RequestIdLayer::current()
}
fn short(&self) -> u32 {
let mut x = ((self.0 & (0xFFFFFFFF << 48)) >> 48) as u32;
x = (x ^ (x >> 16)).wrapping_mul(0x21f0aaad);
x = (x ^ (x >> 15)).wrapping_mul(0x735a2d97);
x = x ^ (x >> 15);
x
}
pub fn layer() -> RequestIdLayer {
RequestIdLayer
}
}
impl RequestIdLayer {
thread_local! {
static CURRENT_REQUEST_ID: Cell<Option<RequestId>> = Cell::new(None);
}
pub fn current() -> Option<RequestId> {
Self::CURRENT_REQUEST_ID.get()
}
}
impl<S: Subscriber + for<'a> LookupSpan<'a>> Layer<S> for RequestIdLayer {
fn on_new_span(&self, _: &Attributes<'_>, id: &Id, ctxt: Context<'_, S>) {
let span = ctxt.span(id).expect("new_span: span does not exist");
if span.name() == "request" {
span.extensions_mut().replace(RequestId::new());
}
}
fn on_enter(&self, id: &Id, ctxt: Context<'_, S>) {
let span = ctxt.span(id).expect("enter: span does not exist");
if span.name() == "request" {
Self::CURRENT_REQUEST_ID.set(RequestId::of(&span));
}
}
fn on_exit(&self, id: &Id, ctxt: Context<'_, S>) {
let span = ctxt.span(id).expect("enter: span does not exist");
if span.name() == "request" {
Self::CURRENT_REQUEST_ID.set(None);
}
}
}
impl fmt::Display for RequestId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.short(), f)
}
}
impl fmt::LowerHex for RequestId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(&self.short(), f)
}
}
impl fmt::UpperHex for RequestId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(&self.short(), f)
}
}
impl Hasher for IdentHasher {
fn finish(&self) -> u64 {
self.0 as u64
}
fn write(&mut self, bytes: &[u8]) {
for &byte in bytes {
self.0 = (self.0 << 8) | (byte as u128);
}
}
fn write_u64(&mut self, i: u64) {
fn shuffle(mut x: u64) -> u64 {
x = x.wrapping_add(1);
x = (x ^ (x >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
x = (x ^ (x >> 27)).wrapping_mul(0x94d049bb133111eb);
x = x ^ (x >> 31);
x
}
self.0 = (self.0 << 64) | shuffle(i) as u128;
}
}