chore: add minimal proxy egress diagnostics (#21220)

## Why
Recent Auto Review reports show Git traffic hanging through the local
proxy on both SSH and HTTPS paths. Today the support bundle does not
make it obvious whether a request is stuck before upstream dialing,
during the proxy hop, or after the upstream response begins, which slows
down root-cause triage.

This adds a small amount of runtime visibility at the existing proxy
boundaries without changing routing or policy behavior.

## What changed
- log whether HTTP and CONNECT traffic take the direct or upstream-proxy
route
- log start / success / failure timings for CONNECT, HTTP, and SOCKS5
upstream dials
- log CONNECT forwarding lifecycle events
- describe HTTP success at the response-header boundary that is actually
observed, rather than implying the full body finished

## Verification
- `cargo test -p codex-network-proxy`
- `cargo clippy -p codex-network-proxy --all-targets -- -D warnings`
This commit is contained in:
viyatb-oai
2026-05-05 10:50:59 -07:00
committed by GitHub
Unverified
parent ed6082c9f9
commit 172303bbfa
3 changed files with 114 additions and 25 deletions
+42 -5
View File
@@ -75,6 +75,7 @@ use std::convert::Infallible;
use std::net::SocketAddr;
use std::net::TcpListener as StdTcpListener;
use std::sync::Arc;
use std::time::Instant;
use tracing::error;
use tracing::info;
use tracing::warn;
@@ -370,6 +371,16 @@ async fn http_connect_proxy(upgraded: Upgraded) -> Result<(), Infallible> {
} else {
None
};
match proxy.as_ref() {
Some(proxy) => info!(
"CONNECT route selected (host={}, port={}, route=upstream_proxy, proxy={})",
target.host, target.port, proxy.address
),
None => info!(
"CONNECT route selected (host={}, port={}, route=direct)",
target.host, target.port
),
}
if let Err(err) = forward_connect_tunnel(upgraded, proxy, app_state).await {
warn!("tunnel error: {err}");
@@ -402,21 +413,47 @@ async fn forward_connect_tunnel(
let connector = TlsConnectorLayer::tunnel(None)
.with_connector_data(tls_config)
.into_layer(proxy_connector);
let EstablishedClientConnection { conn: target, .. } =
connector.connect(req).await.map_err(|err| {
OpaqueError::from_boxed(err)
info!("CONNECT upstream dial started (target={authority})");
let connect_started_at = Instant::now();
let EstablishedClientConnection { conn: target, .. } = match connector.connect(req).await {
Ok(connection) => {
info!(
"CONNECT upstream dial established (target={authority}, elapsed_ms={})",
connect_started_at.elapsed().as_millis()
);
connection
}
Err(err) => {
warn!(
"CONNECT upstream dial failed (target={authority}, elapsed_ms={})",
connect_started_at.elapsed().as_millis()
);
return Err(OpaqueError::from_boxed(err)
.with_context(|| format!("establish CONNECT tunnel to {authority}"))
.into_boxed()
})?;
.into_boxed());
}
};
let proxy_req = ProxyRequest {
source: upgraded,
target,
};
info!("CONNECT tunnel forwarding started (target={authority})");
let forward_started_at = Instant::now();
StreamForwardService::default()
.serve(proxy_req)
.await
.map(|_| {
info!(
"CONNECT tunnel forwarding completed (target={authority}, elapsed_ms={})",
forward_started_at.elapsed().as_millis()
);
})
.map_err(|err| {
warn!(
"CONNECT tunnel forwarding failed (target={authority}, elapsed_ms={})",
forward_started_at.elapsed().as_millis()
);
OpaqueError::from_boxed(err.into())
.with_context(|| format!("forward CONNECT tunnel to {authority}"))
.into_boxed()
+15 -1
View File
@@ -40,6 +40,7 @@ use std::io;
use std::net::SocketAddr;
use std::net::TcpListener as StdTcpListener;
use std::sync::Arc;
use std::time::Instant;
use tracing::error;
use tracing::info;
use tracing::warn;
@@ -290,7 +291,20 @@ async fn handle_socks5_tcp(
}
}
tcp_connector.serve(req).await
info!("SOCKS upstream dial started (host={host}, port={port})");
let connect_started_at = Instant::now();
let result = tcp_connector.serve(req).await;
match &result {
Ok(_) => info!(
"SOCKS upstream dial established (host={host}, port={port}, elapsed_ms={})",
connect_started_at.elapsed().as_millis()
),
Err(_) => warn!(
"SOCKS upstream dial failed (host={host}, port={port}, elapsed_ms={})",
connect_started_at.elapsed().as_millis()
),
}
result
}
async fn inspect_socks5_udp(
+57 -19
View File
@@ -3,7 +3,7 @@ use crate::state::NetworkProxyState;
use rama_core::Layer;
use rama_core::Service;
use rama_core::error::BoxError;
use rama_core::error::ErrorContext as _;
use rama_core::error::ErrorExt as _;
use rama_core::error::OpaqueError;
use rama_core::extensions::ExtensionsMut;
use rama_core::extensions::ExtensionsRef;
@@ -21,6 +21,8 @@ use rama_net::http::RequestContext;
use rama_tls_rustls::client::TlsConnectorDataBuilder;
use rama_tls_rustls::client::TlsConnectorLayer;
use std::sync::Arc;
use std::time::Instant;
use tracing::info;
use tracing::warn;
#[cfg(target_os = "macos")]
@@ -41,13 +43,6 @@ impl ProxyConfig {
Self { http, https, all }
}
fn proxy_for_request(&self, req: &Request) -> Option<ProxyAddress> {
let is_secure = RequestContext::try_from(req)
.map(|ctx| ctx.protocol.is_secure())
.unwrap_or(false);
self.proxy_for_protocol(is_secure)
}
fn proxy_for_protocol(&self, is_secure: bool) -> Option<ProxyAddress> {
if is_secure {
self.https
@@ -155,28 +150,71 @@ impl Service<Request<Body>> for UpstreamClient {
type Error = OpaqueError;
async fn serve(&self, mut req: Request<Body>) -> Result<Self::Output, Self::Error> {
if let Some(proxy) = self.proxy_config.proxy_for_request(&req) {
let request_context = RequestContext::try_from(&req).ok();
let authority = request_context
.as_ref()
.map(|ctx| ctx.host_with_port().to_string())
.unwrap_or_else(|| "<unknown>".to_string());
let proxy = self.proxy_config.proxy_for_protocol(
request_context
.as_ref()
.map(|ctx| ctx.protocol.is_secure())
.unwrap_or(false),
);
match proxy.as_ref() {
Some(proxy) => info!(
"HTTP upstream route selected (target={authority}, route=upstream_proxy, proxy={})",
proxy.address
),
None => info!("HTTP upstream route selected (target={authority}, route=direct)"),
}
if let Some(proxy) = proxy {
req.extensions_mut().insert(proxy);
}
let uri = req.uri().clone();
let connect_started_at = Instant::now();
let EstablishedClientConnection {
input: mut req,
conn: http_connection,
} = self
.connector
.serve(req)
.await
.map_err(OpaqueError::from_boxed)?;
} = match self.connector.serve(req).await {
Ok(connection) => {
info!(
"HTTP upstream connection established (target={authority}, elapsed_ms={})",
connect_started_at.elapsed().as_millis()
);
connection
}
Err(err) => {
warn!(
"HTTP upstream connection failed (target={authority}, elapsed_ms={})",
connect_started_at.elapsed().as_millis()
);
return Err(OpaqueError::from_boxed(err));
}
};
req.extensions_mut()
.extend(http_connection.extensions().clone());
http_connection
.serve(req)
.await
.map_err(OpaqueError::from_boxed)
.with_context(|| format!("http request failure for uri: {uri}"))
let request_started_at = Instant::now();
match http_connection.serve(req).await {
Ok(resp) => {
info!(
"HTTP upstream response headers received (target={authority}, elapsed_ms={})",
request_started_at.elapsed().as_millis()
);
Ok(resp)
}
Err(err) => {
warn!(
"HTTP upstream response headers failed (target={authority}, elapsed_ms={})",
request_started_at.elapsed().as_millis()
);
Err(OpaqueError::from_boxed(err)
.context(format!("http request failure for uri: {uri}")))
}
}
}
}