1use metrics::histogram;
12use std::time::Instant;
13
14#[macro_export]
16macro_rules! timed {
17 ($metric:expr, $($k:expr => $v:expr),+; $block:expr) => {{
18 let __start = std::time::Instant::now();
19 let __result = $block;
20 let __us = __start.elapsed().as_micros() as f64;
21 metrics::histogram!($metric, $($k => $v),+).record(__us);
22 __result
23 }};
24 ($metric:expr; $block:expr) => {{
25 let __start = std::time::Instant::now();
26 let __result = $block;
27 let __us = __start.elapsed().as_micros() as f64;
28 metrics::histogram!($metric).record(__us);
29 __result
30 }};
31}
32
33pub struct TimingGuard {
36 name: &'static str,
37 start: Instant,
38 label_key: Option<&'static str>,
39 label_value: Option<String>,
40}
41
42impl TimingGuard {
43 pub fn new(name: &'static str) -> Self {
45 Self {
46 name,
47 start: Instant::now(),
48 label_key: None,
49 label_value: None,
50 }
51 }
52
53 pub fn with_label(name: &'static str, key: &'static str, value: impl Into<String>) -> Self {
55 Self {
56 name,
57 start: Instant::now(),
58 label_key: Some(key),
59 label_value: Some(value.into()),
60 }
61 }
62}
63
64impl Drop for TimingGuard {
65 fn drop(&mut self) {
66 let elapsed_us = self.start.elapsed().as_micros() as f64;
67 if let (Some(key), Some(value)) = (self.label_key, self.label_value.take()) {
68 histogram!(self.name, key => value).record(elapsed_us);
69 } else {
70 histogram!(self.name).record(elapsed_us);
71 }
72 }
73}
74
75pub mod exchange {
81 pub const HTTP_REQUEST: &str = "openpx.exchange.http_request_us";
83 pub const PARSE_RESPONSE: &str = "openpx.exchange.parse_response_us";
85 pub const SIGN_REQUEST: &str = "openpx.exchange.sign_request_us";
87 pub const WS_SEND: &str = "openpx.exchange.ws_send_us";
89 pub const WS_RECEIVE: &str = "openpx.exchange.ws_receive_us";
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use std::thread::sleep;
97 use std::time::Duration;
98
99 #[test]
100 fn test_timing_guard() {
101 let _guard = TimingGuard::new("test.metric");
103 sleep(Duration::from_micros(100));
104 }
105
106 #[test]
107 fn test_timing_guard_with_label() {
108 let _guard = TimingGuard::with_label("test.metric", "exchange", "polymarket");
109 sleep(Duration::from_micros(100));
110 }
111}