mirror of
https://github.com/openai/codex.git
synced 2026-10-28 18:58:46 +00:00
Add exec-server RPC timing and process startup tracing (#47680)
## Why Detached work can keep request spans open beyond response enqueueing. Record explicit phase timings to distinguish request handling from the full span lifetime. ## What changed - Record server dispatch and response enqueue offsets from request receipt, plus a response enqueue event for HTTP responses that bypass the dispatcher. - Emit client request enqueue and response receipt events, including success or server-error outcomes and reader-to-caller delay. Carry completion timestamps to the awaiting task so receipt events retain its tracing context. - Add spans for process startup, sandbox preparation, shell snapshot preparation and capture, and process spawning. Record process identifiers only when nonempty and at most 64 bytes long. GitOrigin-RevId: 237db898b3284fe8a6a36cb0055b3c7991d8e8a4
This commit is contained in:
committed by
copyberry
parent
8de2d336b8
commit
6fa3bcaae8
@@ -52,6 +52,7 @@ use crate::protocol::FsWalkParams;
|
||||
use crate::protocol::FsWalkResponse;
|
||||
use crate::protocol::FsWriteFileParams;
|
||||
use crate::protocol::FsWriteFileResponse;
|
||||
use crate::protocol::HTTP_REQUEST_METHOD;
|
||||
use crate::protocol::HttpRequestParams;
|
||||
use crate::protocol::InitializeParams;
|
||||
use crate::protocol::InitializeResponse;
|
||||
@@ -292,6 +293,15 @@ impl ExecServerHandler {
|
||||
}
|
||||
return Err(error);
|
||||
}
|
||||
// This response bypasses the dispatcher; record it before body-stream setup.
|
||||
tracing::event!(
|
||||
name: "codex.exec_server.response_enqueued",
|
||||
target: "codex_otel.trace_safe",
|
||||
tracing::Level::INFO,
|
||||
event.name = "codex.exec_server.response_enqueued",
|
||||
rpc.method = HTTP_REQUEST_METHOD,
|
||||
outcome = "success",
|
||||
);
|
||||
if let Some(pending_stream) = pending_stream {
|
||||
self.start_http_body_stream(pending_stream).await;
|
||||
}
|
||||
|
||||
@@ -182,6 +182,10 @@ impl RequestDispatcher {
|
||||
self.telemetry
|
||||
.request_queue_completed(method, queued_at.elapsed());
|
||||
request_span.record("otel.name", method);
|
||||
request_span.record(
|
||||
"rpc.dispatch_offset_ns",
|
||||
i64::try_from(queued_at.elapsed().as_nanos()).unwrap_or(i64::MAX),
|
||||
);
|
||||
if self
|
||||
.outgoing_tx
|
||||
.send(RpcServerOutboundMessage::Error {
|
||||
@@ -203,6 +207,10 @@ impl RequestDispatcher {
|
||||
);
|
||||
return RequestTaskResult::ConnectionClosed;
|
||||
}
|
||||
request_span.record(
|
||||
"rpc.response_enqueue_offset_ns",
|
||||
i64::try_from(queued_at.elapsed().as_nanos()).unwrap_or(i64::MAX),
|
||||
);
|
||||
request_span.record("result", "error");
|
||||
self.telemetry.request_completed(
|
||||
method,
|
||||
@@ -221,6 +229,10 @@ impl RequestDispatcher {
|
||||
let mut disconnected_rx = self.disconnected_rx.clone();
|
||||
let telemetry = self.telemetry.clone();
|
||||
let task = async move {
|
||||
request_span.record(
|
||||
"rpc.dispatch_offset_ns",
|
||||
i64::try_from(queued_at.elapsed().as_nanos()).unwrap_or(i64::MAX),
|
||||
);
|
||||
telemetry.request_queue_completed(
|
||||
method,
|
||||
queued_at.elapsed().saturating_sub(route_setup_duration),
|
||||
@@ -240,10 +252,19 @@ impl RequestDispatcher {
|
||||
};
|
||||
let result = request_result(&message);
|
||||
let response_sent = match message {
|
||||
Some(message) => tokio::select! {
|
||||
result = outgoing_tx.send(message) => result.is_ok(),
|
||||
_ = disconnected_rx.changed() => false,
|
||||
},
|
||||
Some(message) => {
|
||||
let response_sent = tokio::select! {
|
||||
result = outgoing_tx.send(message) => result.is_ok(),
|
||||
_ = disconnected_rx.changed() => false,
|
||||
};
|
||||
if response_sent {
|
||||
request_span.record(
|
||||
"rpc.response_enqueue_offset_ns",
|
||||
i64::try_from(queued_at.elapsed().as_nanos()).unwrap_or(i64::MAX),
|
||||
);
|
||||
}
|
||||
response_sent
|
||||
}
|
||||
None => true,
|
||||
};
|
||||
if !response_sent {
|
||||
|
||||
Reference in New Issue
Block a user