Log curl command line for all requests at trace

This commit is contained in:
Lambda 2024-09-03 20:35:09 +00:00 committed by Charles Hall
parent b0f33207fe
commit 5c4062742f
No known key found for this signature in database
GPG key ID: 7B8E0645816E07CF
3 changed files with 103 additions and 19 deletions

View file

@ -64,7 +64,7 @@ use ruma::{
};
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
use tokio::sync::RwLock;
use tracing::{debug, error, field, warn};
use tracing::{debug, error, field, trace, trace_span, warn};
use super::appservice_server;
use crate::{
@ -253,6 +253,14 @@ where
signature,
)));
// can be enabled selectively using `filter =
// grapevine[outgoing_request_curl]=trace` in config
trace_span!("outgoing_request_curl").in_scope(|| {
trace!(
cmd = utils::curlify(&http_request),
"curl command line for outgoing request"
);
});
let reqwest_request = reqwest::Request::try_from(http_request)?;
let url = reqwest_request.url().clone();

View file

@ -147,26 +147,42 @@ async fn run_server() -> Result<(), error::Serve> {
let middlewares = ServiceBuilder::new()
.sensitive_headers([header::AUTHORIZATION])
.layer(axum::middleware::from_fn(spawn_task))
.layer(TraceLayer::new_for_http().make_span_with(
|request: &http::Request<_>| {
let endpoint = if let Some(endpoint) =
request.extensions().get::<MatchedPath>()
{
endpoint.as_str()
} else {
request.uri().path()
};
.layer(
TraceLayer::new_for_http()
.make_span_with(|request: &http::Request<_>| {
let endpoint = if let Some(endpoint) =
request.extensions().get::<MatchedPath>()
{
endpoint.as_str()
} else {
request.uri().path()
};
let method = request.method();
let method = request.method();
tracing::info_span!(
"http_request",
otel.name = format!("{method} {endpoint}"),
%method,
%endpoint,
)
},
))
tracing::info_span!(
"http_request",
otel.name = format!("{method} {endpoint}"),
%method,
%endpoint,
)
})
.on_request(
|request: &http::Request<_>, _span: &tracing::Span| {
// can be enabled selectively using `filter =
// grapevine[incoming_request_curl]=trace` in config
tracing::trace_span!("incoming_request_curl").in_scope(
|| {
tracing::trace!(
cmd = utils::curlify(request),
"curl command line for incoming request \
(guessed hostname)"
);
},
);
},
),
)
.layer(axum::middleware::from_fn(unrecognized_method))
.layer(
CorsLayer::new()

View file

@ -306,6 +306,66 @@ impl<'a> TryFrom<&'a MxcUri> for MxcData<'a> {
}
}
fn curlify_args<T>(req: &http::Request<T>) -> Option<Vec<String>> {
let mut args =
vec!["curl".to_owned(), "-X".to_owned(), req.method().to_string()];
for (name, val) in req.headers() {
args.extend([
"-H".to_owned(),
format!("{name}: {}", val.to_str().ok()?),
]);
}
let fix_uri = || {
if req.uri().scheme().is_some() {
return None;
}
if req.uri().authority().is_some() {
return None;
}
let mut parts = req.uri().clone().into_parts();
parts.scheme = Some(http::uri::Scheme::HTTPS);
let host =
req.headers().get(http::header::HOST)?.to_str().ok()?.to_owned();
parts.authority =
Some(http::uri::Authority::from_maybe_shared(host).ok()?);
http::uri::Uri::from_parts(parts).ok()
};
let uri = if let Some(new_uri) = fix_uri() {
Cow::Owned(new_uri)
} else {
Cow::Borrowed(req.uri())
};
args.push(uri.to_string());
Some(args)
}
pub(crate) fn curlify<T>(req: &http::Request<T>) -> Option<String> {
let args = curlify_args(req)?;
Some(
args.into_iter()
.map(|arg| {
if arg.chars().all(|c| {
c.is_alphanumeric() || ['-', '_', ':', '/'].contains(&c)
}) {
arg
} else {
format!("'{}'", arg.replace('\'', "\\'"))
}
})
.collect::<Vec<_>>()
.join(" "),
)
}
#[cfg(test)]
mod tests {
use crate::utils::dbg_truncate_str;