mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[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:
@@ -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 {
|
||||
|
||||
@@ -29,6 +29,7 @@ pub use crate::provider::OtelProvider;
|
||||
pub use crate::trace_context::context_from_w3c_trace_context;
|
||||
pub use crate::trace_context::current_span_trace_id;
|
||||
pub use crate::trace_context::current_span_w3c_trace_context;
|
||||
pub use crate::trace_context::inject_span_w3c_trace_headers;
|
||||
pub use crate::trace_context::set_parent_from_context;
|
||||
pub use crate::trace_context::set_parent_from_w3c_trace_context;
|
||||
pub use crate::trace_context::span_w3c_trace_context;
|
||||
|
||||
@@ -49,6 +49,38 @@ pub fn span_w3c_trace_context(span: &Span) -> Option<W3cTraceContext> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Injects the W3C trace context for `span` into HTTP headers.
|
||||
///
|
||||
/// Existing `traceparent` and `tracestate` values are replaced so callers can
|
||||
/// safely reuse a request header map while keeping the supplied span as the
|
||||
/// source of truth.
|
||||
pub fn inject_span_w3c_trace_headers(span: &Span, headers: &mut http::HeaderMap) -> bool {
|
||||
let Some(trace) = span_w3c_trace_context(span) else {
|
||||
return false;
|
||||
};
|
||||
match trace.traceparent {
|
||||
Some(traceparent) => {
|
||||
if let Ok(value) = http::HeaderValue::from_str(&traceparent) {
|
||||
headers.insert("traceparent", value);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
headers.remove("traceparent");
|
||||
}
|
||||
}
|
||||
match trace.tracestate {
|
||||
Some(tracestate) => {
|
||||
if let Ok(value) = http::HeaderValue::from_str(&tracestate) {
|
||||
headers.insert("tracestate", value);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
headers.remove("tracestate");
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn set_tracestate_entries(
|
||||
entries: BTreeMap<String, BTreeMap<String, String>>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
Reference in New Issue
Block a user