For advanced tracing requirements, such as calculating custom metrics (e.g., request elapsed time) or adding custom attributes to spans, implement the ReqwestOtelSpanBackend trait.
This trait requires two methods:
on_request_start: Called when the request begins. Use this to initialize spans (often using the reqwest_otel_span! macro) and store initial state in the request Extensions.on_request_end: Called when the request completes. Use this to record final attributes, handle outcomes (success/failure), and clean up state.
When using a custom backend, initialize the middleware using TracingMiddleware::<YourBackend>::new().
use reqwest_middleware::Result;
use http::Extensions;
use reqwest::{Request, Response};
use reqwest_middleware::ClientBuilder;
use reqwest_tracing::{
default_on_request_end, reqwest_otel_span, ReqwestOtelSpanBackend, TracingMiddleware
};
use tracing::Span;
use std::time::{Duration, Instant};
pub struct TimeTrace;
impl ReqwestOtelSpanBackend for TimeTrace {
fn on_request_start(req: &Request, extension: &mut Extensions) -> Span {
extension.insert(Instant::now());
reqwest_otel_span!(name="example-request", req, time_elapsed = tracing::field::Empty)
}
fn on_request_end(span: &Span, outcome: &Result<Response>, extension: &mut Extensions) {
let time_elapsed = extension.get::<Instant>().unwrap().elapsed().as_millis() as i64;
default_on_request_end(span, outcome);
span.record("time_elapsed", &time_elapsed);
}
}
let http = ClientBuilder::new(reqwest::Client::new())
.with(TracingMiddleware::<TimeTrace>::new())
.build();