spin_trigger_http/
instrument.rs1use anyhow::Result;
2use http::Response;
3use tracing::Level;
4
5use crate::Body;
6
7macro_rules! http_span {
9 ($request:tt, $addr:tt) => {
10 tracing::info_span!(
11 "spin_trigger_http.handle_http_request",
12 "otel.kind" = "server",
13 "http.request.method" = %$request.method(),
14 "network.peer.address" = %$addr.ip(),
15 "network.peer.port" = %$addr.port(),
16 "network.protocol.name" = "http",
17 "url.path" = $request.uri().path(),
18 "url.query" = $request.uri().query().unwrap_or(""),
19 "url.scheme" = $request.uri().scheme_str().unwrap_or(""),
20 "client.address" = $request.headers().get("x-forwarded-for").and_then(|val| val.to_str().ok()),
21 "error.type" = ::tracing::field::Empty,
23 "http.response.status_code" = ::tracing::field::Empty,
24 "http.route" = ::tracing::field::Empty,
25 "otel.name" = ::tracing::field::Empty,
26 )
27 };
28}
29
30pub(crate) use http_span;
31
32pub(crate) fn finalize_http_span(
34 response: Result<Response<Body>>,
35 method: String,
36) -> Result<Response<Body>> {
37 let span = tracing::Span::current();
38 match response {
39 Ok(response) => {
40 tracing::info!(
41 "Request finished, sending response with status code {}",
42 response.status()
43 );
44
45 let matched_route = response.extensions().get::<MatchedRoute>();
46 if let Some(MatchedRoute { route }) = matched_route {
48 span.record("http.route", route);
49 span.record("otel.name", format!("{method} {route}"));
50 } else {
51 span.record("otel.name", method);
52 }
53
54 span.record("http.response.status_code", response.status().as_u16());
56
57 Ok(response)
58 }
59 Err(err) => {
60 instrument_error(&err);
61 span.record("http.response.status_code", 500);
62 span.record("otel.name", method);
63 Err(err)
64 }
65 }
66}
67
68pub(crate) fn instrument_error(err: &anyhow::Error) {
70 let span = tracing::Span::current();
71 tracing::event!(target:module_path!(), Level::INFO, error = %err);
72 span.record("error.type", format!("{:?}", err));
73}
74
75#[derive(Clone)]
78pub struct MatchedRoute {
79 pub route: String,
80}
81
82impl MatchedRoute {
83 pub fn set_response_extension(resp: &mut Response<Body>, route: impl Into<String>) {
84 resp.extensions_mut().insert(MatchedRoute {
85 route: route.into(),
86 });
87 }
88
89 pub fn with_response_extension(
90 mut resp: Response<Body>,
91 route: impl Into<String>,
92 ) -> Response<Body> {
93 Self::set_response_extension(&mut resp, route);
94 resp
95 }
96}