[codex] Propagate traces through exec-server HTTP (#30117)

Fixes distributed trace continuity across exec-server JSON-RPC HTTP
egress by adding an executor client span and injecting its W3C context
through a reusable `codex-otel` helper.

This preserves the caller trace across core/tool → executor →
provider/MCP instead of dropping parentage at raw reqwest.

Note that this doesn't include the websocket path, which is needed to
really get the full story but at least we cover the basic http path with
this change.
This commit is contained in:
Tom
2026-06-25 23:22:22 +00:00
committed by GitHub
parent 5eebeb8169
commit 8ce931ab76
3 changed files with 48 additions and 2 deletions
@@ -18,6 +18,7 @@ use reqwest::Url;
use reqwest::header::HeaderMap;
use reqwest::header::HeaderName;
use reqwest::header::HeaderValue;
use tracing::Instrument;
use super::HttpResponseBodyStream;
use super::response_body_stream::send_body_delta;
@@ -146,15 +147,26 @@ impl ReqwestHttpRequestRunner {
}
}
let headers = Self::build_headers(params.headers)?;
let request_span = tracing::info_span!(
"codex.exec_server.http_request",
otel.kind = "client",
http.request.method = method.as_str(),
server.address = url.host_str().unwrap_or_default(),
server.port = u64::from(url.port_or_known_default().unwrap_or_default()),
http.response.status_code = tracing::field::Empty,
error.type = tracing::field::Empty,
);
let mut headers = Self::build_headers(params.headers)?;
codex_otel::inject_span_w3c_trace_headers(&request_span, &mut headers);
let mut request = self.client.request(method.clone(), url).headers(headers);
if let Some(body) = params.body {
request = request.body(body.into_inner());
}
let response = match request.send().await {
let response = match request.send().instrument(request_span.clone()).await {
Ok(response) => response,
Err(error) => {
request_span.record("error.type", "request");
let error_message = error.to_string();
log_send_error(&method, error);
return Err(internal_error(format!(
@@ -163,6 +175,7 @@ impl ReqwestHttpRequestRunner {
}
};
let status = response.status().as_u16();
request_span.record("http.response.status_code", u64::from(status));
let headers = Self::response_headers(response.headers());
if params.stream_response {