include traceresponse header if possible

This can help with debugging.
This commit is contained in:
Charles Hall 2024-09-22 11:01:33 -07:00
parent 9add9a1e96
commit 6ab87f97dd
No known key found for this signature in database
GPG key ID: 7B8E0645816E07CF
3 changed files with 54 additions and 4 deletions

View file

@ -248,3 +248,6 @@ This will be the first release of Grapevine since it was forked from Conduit
[!102](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/102))
19. Allow configuring the served API components per listener.
([!109](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/109))
20. Include the [`traceresponse` header](https://w3c.github.io/trace-context/#traceresponse-header)
if OpenTelemetry Tracing is in use.
([!112](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/112))

View file

@ -171,7 +171,8 @@ async fn run_server() -> Result<(), error::Serve> {
.try_into()
.expect("failed to convert max request size"),
))
.layer(axum::middleware::from_fn(observability::http_metrics_layer));
.layer(axum::middleware::from_fn(observability::http_metrics_layer))
.layer(axum::middleware::from_fn(observability::traceresponse_layer));
let mut handles = Vec::new();
let mut servers = JoinSet::new();

View file

@ -18,9 +18,13 @@ use opentelemetry_sdk::{
};
use strum::{AsRefStr, IntoStaticStr};
use tokio::time::Instant;
use tracing::Span;
use tracing_flame::{FlameLayer, FlushGuard};
use tracing_opentelemetry::OtelData;
use tracing_subscriber::{
layer::SubscriberExt, reload, EnvFilter, Layer, Registry,
layer::SubscriberExt,
registry::{LookupSpan, SpanData},
reload, EnvFilter, Layer, Registry,
};
use crate::{
@ -138,8 +142,7 @@ fn make_backend<S, L, T>(
>
where
L: Layer<S>,
S: tracing::Subscriber
+ for<'span> tracing_subscriber::registry::LookupSpan<'span>,
S: tracing::Subscriber + for<'span> LookupSpan<'span>,
{
if !enable {
return Ok((None, None, None));
@ -423,3 +426,46 @@ pub(crate) async fn http_metrics_layer(req: Request, next: Next) -> Response {
}
}
}
/// Add `traceresponse` header if possible
///
/// See also <https://w3c.github.io/trace-context/#traceresponse-header>.
pub(crate) async fn traceresponse_layer(req: Request, next: Next) -> Response {
let mut resp = next.run(req).await;
let ids = tracing::dispatcher::get_default(|dispatch| {
Span::current()
.id()
.and_then(|id| {
dispatch
.downcast_ref::<Registry>()
.and_then(|x| x.span_data(&id))
})
.and_then(|x| {
x.extensions()
.get::<OtelData>()
.and_then(|x| x.builder.trace_id.zip(x.builder.span_id))
})
});
if let Some((trace_id, span_id)) = ids {
let headers = resp.headers_mut();
headers.insert(
"traceresponse",
format!(
"{:02x}-{}-{}-{:02x}",
0,
trace_id,
span_id,
// Doesn't seem to be possible to get the SpanContext here, but
// this should be a fine default value
0,
)
.try_into()
.expect("traceresponse value should be a valid header value"),
);
}
resp
}