Skip to content

Commit 3a391a8

Browse files
committed
Fix HTTP request tracing and make the DNS resolver traced again
1 parent 61d67b8 commit 3a391a8

File tree

10 files changed

+81
-36
lines changed

10 files changed

+81
-36
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ features = ["derive"]
107107
version = "0.10.19"
108108
features = ["env", "yaml", "test"]
109109

110+
# Utilities for dealing with futures
111+
[workspace.dependencies.futures-util]
112+
version = "0.3.31"
113+
110114
# Rate-limiting
111115
[workspace.dependencies.governor]
112116
version = "0.7.0"

crates/axum-utils/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ axum-extra.workspace = true
1818
bytes.workspace = true
1919
chrono.workspace = true
2020
data-encoding = "2.6.0"
21-
futures-util = "0.3.31"
21+
futures-util.workspace = true
2222
headers.workspace = true
2323
http.workspace = true
2424
http-body.workspace = true

crates/handlers/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ workspace = true
1515
# Async runtime
1616
tokio.workspace = true
1717
tokio-util.workspace = true
18-
futures-util = "0.3.31"
18+
futures-util.workspace = true
1919
async-trait.workspace = true
2020

2121
# Logging and tracing

crates/http/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ repository.workspace = true
1212
workspace = true
1313

1414
[dependencies]
15+
futures-util.workspace = true
1516
headers.workspace = true
1617
http.workspace = true
1718
hyper-util.workspace = true
@@ -20,6 +21,7 @@ opentelemetry-semantic-conventions.workspace = true
2021
opentelemetry.workspace = true
2122
reqwest.workspace = true
2223
rustls-platform-verifier.workspace = true
24+
tower.workspace = true
2325
tower-http.workspace = true
2426
tracing.workspace = true
2527
tracing-opentelemetry.workspace = true

crates/http/src/reqwest.rs

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
// SPDX-License-Identifier: AGPL-3.0-only
44
// Please see LICENSE in the repository root for full details.
55

6-
use std::{future::Future, time::Duration};
6+
use std::{future::Future, str::FromStr, sync::Arc, time::Duration};
77

8+
use futures_util::FutureExt as _;
89
use headers::{ContentLength, HeaderMapExt as _, Host, UserAgent};
9-
use hyper_util::client::legacy::connect::HttpInfo;
10+
use hyper_util::client::legacy::connect::{
11+
dns::{GaiResolver, Name},
12+
HttpInfo,
13+
};
1014
use opentelemetry_http::HeaderInjector;
1115
use opentelemetry_semantic_conventions::{
1216
attribute::{HTTP_REQUEST_BODY_SIZE, HTTP_RESPONSE_BODY_SIZE},
@@ -16,21 +20,50 @@ use opentelemetry_semantic_conventions::{
1620
USER_AGENT_ORIGINAL,
1721
},
1822
};
23+
use tower::{BoxError, Service as _};
1924
use tracing::Instrument;
2025
use tracing_opentelemetry::OpenTelemetrySpanExt;
2126

2227
static USER_AGENT: &str = concat!("matrix-authentication-service/", env!("CARGO_PKG_VERSION"));
2328

29+
struct TracingResolver {
30+
inner: GaiResolver,
31+
}
32+
33+
impl TracingResolver {
34+
fn new() -> Self {
35+
let inner = GaiResolver::new();
36+
Self { inner }
37+
}
38+
}
39+
40+
impl reqwest::dns::Resolve for TracingResolver {
41+
fn resolve(&self, name: reqwest::dns::Name) -> reqwest::dns::Resolving {
42+
let span = tracing::info_span!("dns.resolve", name = name.as_str());
43+
let inner = &mut self.inner.clone();
44+
Box::pin(
45+
inner
46+
.call(Name::from_str(name.as_str()).unwrap())
47+
.map(|result| {
48+
result
49+
.map(|addrs| -> reqwest::dns::Addrs { Box::new(addrs) })
50+
.map_err(|err| -> BoxError { Box::new(err) })
51+
})
52+
.instrument(span),
53+
)
54+
}
55+
}
56+
2457
/// Create a new [`reqwest::Client`] with sane parameters
2558
///
2659
/// # Panics
2760
///
2861
/// Panics if the client fails to build, which should never happen
2962
#[must_use]
3063
pub fn client() -> reqwest::Client {
31-
// TODO: make the resolver tracing again
3264
// TODO: can/should we limit in-flight requests?
3365
reqwest::Client::builder()
66+
.dns_resolver(Arc::new(TracingResolver::new()))
3467
.use_preconfigured_tls(rustls_platform_verifier::tls_config())
3568
.user_agent(USER_AGENT)
3669
.timeout(Duration::from_secs(60))
@@ -74,7 +107,6 @@ async fn send_traced(
74107
{ USER_AGENT_ORIGINAL } = user_agent,
75108
"rust.error" = tracing::field::Empty,
76109
);
77-
let _guard = span.enter();
78110

79111
// Inject the span context into the request headers
80112
let context = span.context();
@@ -83,37 +115,42 @@ async fn send_traced(
83115
propagator.inject_context(&context, &mut injector);
84116
});
85117

86-
match client.execute(request).in_current_span().await {
87-
Ok(response) => {
88-
span.record("otel.status_code", "OK");
89-
span.record(HTTP_RESPONSE_STATUS_CODE, response.status().as_u16());
118+
async move {
119+
let span = tracing::Span::current();
120+
match client.execute(request).await {
121+
Ok(response) => {
122+
span.record("otel.status_code", "OK");
123+
span.record(HTTP_RESPONSE_STATUS_CODE, response.status().as_u16());
90124

91-
if let Some(ContentLength(content_length)) = response.headers().typed_get() {
92-
span.record(HTTP_RESPONSE_BODY_SIZE, content_length);
93-
}
125+
if let Some(ContentLength(content_length)) = response.headers().typed_get() {
126+
span.record(HTTP_RESPONSE_BODY_SIZE, content_length);
127+
}
94128

95-
if let Some(http_info) = response.extensions().get::<HttpInfo>() {
96-
let local = http_info.local_addr();
97-
let remote = http_info.remote_addr();
98-
99-
let family = if local.is_ipv4() { "ipv4" } else { "ipv6" };
100-
span.record(NETWORK_TYPE, family);
101-
span.record(CLIENT_ADDRESS, remote.ip().to_string());
102-
span.record(CLIENT_PORT, remote.port());
103-
span.record(SERVER_ADDRESS, local.ip().to_string());
104-
span.record(SERVER_PORT, local.port());
105-
} else {
106-
tracing::warn!("No HttpInfo injected in response extensions");
107-
}
129+
if let Some(http_info) = response.extensions().get::<HttpInfo>() {
130+
let local = http_info.local_addr();
131+
let remote = http_info.remote_addr();
108132

109-
Ok(response)
110-
}
111-
Err(err) => {
112-
span.record("otel.status_code", "ERROR");
113-
span.record("rust.error", &err as &dyn std::error::Error);
114-
Err(err)
133+
let family = if local.is_ipv4() { "ipv4" } else { "ipv6" };
134+
span.record(NETWORK_TYPE, family);
135+
span.record(CLIENT_ADDRESS, remote.ip().to_string());
136+
span.record(CLIENT_PORT, remote.port());
137+
span.record(SERVER_ADDRESS, local.ip().to_string());
138+
span.record(SERVER_PORT, local.port());
139+
} else {
140+
tracing::warn!("No HttpInfo injected in response extensions");
141+
}
142+
143+
Ok(response)
144+
}
145+
Err(err) => {
146+
span.record("otel.status_code", "ERROR");
147+
span.record("rust.error", &err as &dyn std::error::Error);
148+
Err(err)
149+
}
115150
}
116151
}
152+
.instrument(span)
153+
.await
117154
}
118155

119156
/// An extension trait implemented for [`reqwest::RequestBuilder`] to send a

crates/iana-codegen/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ async-trait.workspace = true
1717
camino.workspace = true
1818
convert_case = "0.6.0"
1919
csv = "1.3.0"
20-
futures-util = "0.3.31"
20+
futures-util.workspace = true
2121
reqwest.workspace = true
2222
serde.workspace = true
2323
tokio.workspace = true

crates/listener/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ workspace = true
1313

1414
[dependencies]
1515
bytes.workspace = true
16-
futures-util = "0.3.31"
16+
futures-util.workspace = true
1717
http-body.workspace = true
1818
hyper = { workspace = true, features = ["server"] }
1919
hyper-util.workspace = true

crates/storage-pg/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ serde.workspace = true
2121
serde_json.workspace = true
2222
thiserror.workspace = true
2323
tracing.workspace = true
24-
futures-util = "0.3.31"
24+
futures-util.workspace = true
2525
opentelemetry-semantic-conventions.workspace = true
2626

2727
rand.workspace = true

crates/storage/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ workspace = true
1515
async-trait.workspace = true
1616
chrono.workspace = true
1717
thiserror.workspace = true
18-
futures-util = "0.3.31"
18+
futures-util.workspace = true
1919

2020
apalis-core = { version = "0.4.9", features = ["tokio-comp"] }
2121
opentelemetry.workspace = true

0 commit comments

Comments
 (0)