Skip to content

Commit d08b9c7

Browse files
committed
feat(outbound-http): Trace outbound-http host component
Signed-off-by: Caleb Schoepp <[email protected]>
1 parent c5066c4 commit d08b9c7

File tree

3 files changed

+30
-2
lines changed

3 files changed

+30
-2
lines changed

Cargo.lock

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

crates/outbound-http/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@ spin-expressions = { path = "../expressions", optional = true }
1717
spin-locked-app = { path = "../locked-app" }
1818
spin-outbound-networking = { path = "../outbound-networking" }
1919
spin-world = { path = "../world", optional = true }
20+
spin-telemetry = { path = "../telemetry" }
2021
terminal = { path = "../terminal" }
2122
tracing = { workspace = true }
2223
url = "2.2.1"
2324

2425
[features]
2526
default = ["runtime"]
2627
runtime = ["dep:spin-app", "dep:spin-core", "dep:spin-expressions", "dep:spin-world"]
28+
29+
[lints]
30+
workspace = true

crates/outbound-http/src/host_impl.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use anyhow::Result;
2-
use http::HeaderMap;
2+
use http::{HeaderMap, Uri};
33
use reqwest::Client;
44
use spin_core::async_trait;
55
use spin_outbound_networking::{AllowedHostsConfig, OutboundUrl};
66
use spin_world::v1::{
77
http as outbound_http,
88
http_types::{Headers, HttpError, Method, Request, Response},
99
};
10+
use tracing::{field::Empty, instrument, Level};
1011

1112
/// A very simple implementation for outbound HTTP requests.
1213
#[derive(Default, Clone)]
@@ -38,8 +39,28 @@ impl OutboundHttp {
3839

3940
#[async_trait]
4041
impl outbound_http::Host for OutboundHttp {
42+
#[instrument(name = "spin_outbound_http.send_request", skip_all, err(level = Level::INFO),
43+
fields(otel.kind = "client", url.full = Empty, http.request.method = Empty,
44+
http.response.status_code = Empty, otel.name = Empty, server.address = Empty, server.port = Empty))]
4145
async fn send_request(&mut self, req: Request) -> Result<Result<Response, HttpError>> {
4246
Ok(async {
47+
let current_span = tracing::Span::current();
48+
let method = format!("{:?}", req.method)
49+
.strip_prefix("Method::")
50+
.unwrap_or("_OTHER")
51+
.to_uppercase();
52+
current_span.record("otel.name", method.clone());
53+
current_span.record("url.full", req.uri.clone());
54+
current_span.record("http.request.method", method);
55+
if let Ok(uri) = req.uri.parse::<Uri>() {
56+
if let Some(authority) = uri.authority() {
57+
current_span.record("server.address", authority.host());
58+
if let Some(port) = authority.port() {
59+
current_span.record("server.port", port.as_u16());
60+
}
61+
}
62+
}
63+
4364
tracing::log::trace!("Attempting to send outbound HTTP request to {}", req.uri);
4465
if !self
4566
.is_allowed(&req.uri)
@@ -63,7 +84,8 @@ impl outbound_http::Host for OutboundHttp {
6384

6485
let req_url = reqwest::Url::parse(&abs_url).map_err(|_| HttpError::InvalidUrl)?;
6586

66-
let headers = request_headers(req.headers).map_err(|_| HttpError::RuntimeError)?;
87+
let mut headers = request_headers(req.headers).map_err(|_| HttpError::RuntimeError)?;
88+
spin_telemetry::inject_trace_context(&mut headers);
6789
let body = req.body.unwrap_or_default().to_vec();
6890

6991
if !req.params.is_empty() {
@@ -82,6 +104,7 @@ impl outbound_http::Host for OutboundHttp {
82104
.await
83105
.map_err(log_reqwest_error)?;
84106
tracing::log::trace!("Returning response from outbound request to {}", req.uri);
107+
current_span.record("http.response.status_code", resp.status().as_u16());
85108
response_from_reqwest(resp).await
86109
}
87110
.await)

0 commit comments

Comments
 (0)