tide_server_timing/
middleware.rs1use tide::{Next, Request};
2use tracing_futures::Instrument;
3
4use http_types::trace::{Metric, ServerTiming};
5
6use crate::span_ext::SpanExt;
7
8#[derive(Debug)]
10pub struct TimingMiddleware {
11 _priv: (),
12}
13
14impl TimingMiddleware {
15 pub fn new() -> Self {
17 Self { _priv: () }
18 }
19}
20
21#[tide::utils::async_trait]
22impl<State: Clone + Send + Sync + 'static> tide::Middleware<State> for TimingMiddleware {
23 async fn handle(&self, req: Request<State>, next: Next<'_, State>) -> tide::Result {
24 let res = async move {
27 let span = tracing::Span::current();
29 span.insert_ext(crate::SpanRootTiming);
30
31 let mut res = async move { next.run(req).await }
33 .instrument(tracing::info_span!("tide endpoint handler"))
34 .await;
35
36 let span = tracing::span::Span::current();
38 span.take_ext(|timings: crate::SpanTiming| {
39 let raw_timings = timings.flatten();
40 let mut timings = ServerTiming::new();
41
42 for timing in raw_timings {
43 let dur = match timing.end_time {
44 Some(end_time) => end_time.duration_since(timing.start_time),
45 None => continue, };
47
48 let name = timing.id.into_u64().to_string();
49 let desc = format!("{} ({})", timing.span_name, timing.target);
50
51 let metric = Metric::new(name, Some(dur), Some(desc))
52 .expect("Invalid metric formatting");
53 timings.push(metric);
54 }
55 timings.apply(&mut res);
56 });
57 res
58 }
59 .instrument(tracing::info_span!("tide-server-wrapper"))
60 .await;
61 Ok(res)
62 }
63}