use metrics::histogram;
use std::time::Instant;
#[macro_export]
macro_rules! timed {
($metric:expr, $($k:expr => $v:expr),+; $block:expr) => {{
let __start = std::time::Instant::now();
let __result = $block;
let __us = __start.elapsed().as_micros() as f64;
metrics::histogram!($metric, $($k => $v),+).record(__us);
__result
}};
($metric:expr; $block:expr) => {{
let __start = std::time::Instant::now();
let __result = $block;
let __us = __start.elapsed().as_micros() as f64;
metrics::histogram!($metric).record(__us);
__result
}};
}
pub struct TimingGuard {
name: &'static str,
start: Instant,
label_key: Option<&'static str>,
label_value: Option<String>,
}
impl TimingGuard {
pub fn new(name: &'static str) -> Self {
Self {
name,
start: Instant::now(),
label_key: None,
label_value: None,
}
}
pub fn with_label(name: &'static str, key: &'static str, value: impl Into<String>) -> Self {
Self {
name,
start: Instant::now(),
label_key: Some(key),
label_value: Some(value.into()),
}
}
}
impl Drop for TimingGuard {
fn drop(&mut self) {
let elapsed_us = self.start.elapsed().as_micros() as f64;
if let (Some(key), Some(value)) = (self.label_key, self.label_value.take()) {
histogram!(self.name, key => value).record(elapsed_us);
} else {
histogram!(self.name).record(elapsed_us);
}
}
}
pub mod exchange {
pub const HTTP_REQUEST: &str = "openpx.exchange.http_request_us";
pub const PARSE_RESPONSE: &str = "openpx.exchange.parse_response_us";
pub const SIGN_REQUEST: &str = "openpx.exchange.sign_request_us";
pub const WS_SEND: &str = "openpx.exchange.ws_send_us";
pub const WS_RECEIVE: &str = "openpx.exchange.ws_receive_us";
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread::sleep;
use std::time::Duration;
#[test]
fn test_timing_guard() {
let _guard = TimingGuard::new("test.metric");
sleep(Duration::from_micros(100));
}
#[test]
fn test_timing_guard_with_label() {
let _guard = TimingGuard::with_label("test.metric", "exchange", "polymarket");
sleep(Duration::from_micros(100));
}
}