tide_trace/
lib.rs

1use std::ffi::CString;
2use std::os::raw::c_char;
3use std::os::raw::c_int;
4use std::sync::atomic::{AtomicI32, Ordering};
5use std::sync::Arc;
6use tide::{Middleware, Next, Request, Result};
7
8/// Trace utility for incoming requests and responses.
9///
10/// # Examples
11///
12/// ```
13///     let mut app = tide::new();
14///     app.with(tide_trace::USDTMiddleware::new());
15/// ```
16#[derive(Debug, Clone)]
17pub struct USDTMiddleware {
18    reqid: Arc<AtomicI32>,
19}
20impl USDTMiddleware {
21    /// Create a new instance of `USDTMiddleware`.
22    pub fn new() -> Self {
23        Self {
24            reqid: Arc::new(<AtomicI32>::new(1)),
25        }
26    }
27}
28
29#[tide::utils::async_trait]
30impl<State: Clone + Send + Sync + 'static> Middleware<State> for USDTMiddleware {
31    async fn handle(&self, req: Request<State>, next: Next<'_, State>) -> Result {
32        //async move {
33            let count = self.reqid.fetch_add(1, Ordering::SeqCst);
34            let path = CString::new(req.url().path().to_owned()).expect("CString::new path failed");
35            let method =
36                CString::new(req.method().to_string()).expect("CString::new method failed");
37            let req_headers_coll = req
38                .iter()
39                .map(|h| format!("{:?};", h))
40                .collect::<Vec<String>>()
41                .join("; ");
42            let req_headers = CString::new(req_headers_coll).expect("CString::new header failed");
43            unsafe {
44                startroute(method.as_ptr(), path.as_ptr(), count, req_headers.as_ptr());
45            }
46
47            let res = next.run(req).await;
48            let status = res.status() as i32;
49            let res_headers_coll = res
50                .iter()
51                .map(|h| format!("{:?};", h))
52                .collect::<Vec<String>>()
53                .join("; ");
54            let res_headers = CString::new(res_headers_coll).expect("CString::new header failed");
55            unsafe {
56                endroute(
57                    method.as_ptr(),
58                    path.as_ptr(),
59                    count,
60                    status,
61                    res_headers.as_ptr(),
62                );
63            }
64            self.reqid.load(Ordering::SeqCst);
65            Ok(res)
66        // }
67    }
68}
69
70extern "C" {
71    fn startroute(method: *const c_char, path: *const c_char, reqid: c_int, headers: *const c_char);
72    fn endroute(
73        method: *const c_char,
74        path: *const c_char,
75        reqid: c_int,
76        status: c_int,
77        headers: *const c_char,
78    );
79    fn fire(tag: *const c_char, data: *const c_char);
80}
81/// Trace utility for incoming requests and responses.
82///
83/// # Examples
84///
85/// ```
86/// tide_trace::probe("identifier".to_string(), "data to log".to_string());
87/// ```
88pub fn probe(tag: String, data: String) {
89    let c_data = CString::new(data).expect("CString::new data failed");
90    let c_tag = CString::new(tag).expect("CString::new tag failed");
91    unsafe {
92        fire(c_tag.as_ptr(), c_data.as_ptr());
93    }
94}