mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
feat(core, tracing): add a span representing a turn (#13424)
This is PR 3 of the app-server tracing rollout. PRs https://github.com/openai/codex/pull/13285 and https://github.com/openai/codex/pull/13368 gave us inbound request spans in app-server and propagated trace context through Submission. This change finishes the next piece in core: when a request actually starts a turn, we now create a core-owned long-lived span that stays open for the real lifetime of the turn. What changed: - `Session::spawn_task` can now optionally create a long-lived turn span and run the spawned task inside it - `turn/start` uses that path, so normal turn execution stays under a single core-owned span after the async handoff - `review/start` uses the same pattern - added a unit test that verifies the spawned turn task inherits the submission dispatch trace ancestry **Why** The app-server request span is intentionally short-lived. Once work crosses into core, we still want one span that covers the actual execution window until completion or interruption. This keeps that ownership where it belongs: in the layer that owns the runtime lifecycle.
This commit is contained in:
@@ -17,6 +17,10 @@ impl SessionTask for CompactTask {
|
||||
TaskKind::Compact
|
||||
}
|
||||
|
||||
fn span_name(&self) -> &'static str {
|
||||
"session_task.compact"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
self: Arc<Self>,
|
||||
session: Arc<SessionTaskContext>,
|
||||
|
||||
@@ -32,6 +32,10 @@ impl SessionTask for GhostSnapshotTask {
|
||||
TaskKind::Regular
|
||||
}
|
||||
|
||||
fn span_name(&self) -> &'static str {
|
||||
"session_task.ghost_snapshot"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
self: Arc<Self>,
|
||||
session: Arc<SessionTaskContext>,
|
||||
|
||||
@@ -14,7 +14,7 @@ use tokio::sync::Notify;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tokio_util::task::AbortOnDropHandle;
|
||||
use tracing::Instrument;
|
||||
use tracing::Span;
|
||||
use tracing::info_span;
|
||||
use tracing::trace;
|
||||
use tracing::warn;
|
||||
|
||||
@@ -89,6 +89,9 @@ pub(crate) trait SessionTask: Send + Sync + 'static {
|
||||
/// surface it in telemetry and UI.
|
||||
fn kind(&self) -> TaskKind;
|
||||
|
||||
/// Returns the tracing name for a spawned task span.
|
||||
fn span_name(&self) -> &'static str;
|
||||
|
||||
/// Executes the task until completion or cancellation.
|
||||
///
|
||||
/// Implementations typically stream protocol events using `session` and
|
||||
@@ -127,6 +130,7 @@ impl Session {
|
||||
|
||||
let task: Arc<dyn SessionTask> = Arc::new(task);
|
||||
let task_kind = task.kind();
|
||||
let span_name = task.span_name();
|
||||
|
||||
let cancellation_token = CancellationToken::new();
|
||||
let done = Arc::new(Notify::new());
|
||||
@@ -137,7 +141,15 @@ impl Session {
|
||||
let ctx = Arc::clone(&turn_context);
|
||||
let task_for_run = Arc::clone(&task);
|
||||
let task_cancellation_token = cancellation_token.child_token();
|
||||
let session_span = Span::current();
|
||||
// Task-owned turn spans keep a core-owned span open for the
|
||||
// full task lifecycle after the submission dispatch span ends.
|
||||
let task_span = info_span!(
|
||||
"turn",
|
||||
otel.name = span_name,
|
||||
thread.id = %self.conversation_id,
|
||||
turn.id = %turn_context.sub_id,
|
||||
model = %turn_context.model_info.slug,
|
||||
);
|
||||
tokio::spawn(
|
||||
async move {
|
||||
let ctx_for_finish = Arc::clone(&ctx);
|
||||
@@ -158,7 +170,7 @@ impl Session {
|
||||
}
|
||||
done_clone.notify_waiters();
|
||||
}
|
||||
.instrument(session_span),
|
||||
.instrument(task_span),
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
@@ -68,6 +68,10 @@ impl SessionTask for RegularTask {
|
||||
TaskKind::Regular
|
||||
}
|
||||
|
||||
fn span_name(&self) -> &'static str {
|
||||
"session_task.turn"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
self: Arc<Self>,
|
||||
session: Arc<SessionTaskContext>,
|
||||
|
||||
@@ -43,6 +43,10 @@ impl SessionTask for ReviewTask {
|
||||
TaskKind::Review
|
||||
}
|
||||
|
||||
fn span_name(&self) -> &'static str {
|
||||
"session_task.review"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
self: Arc<Self>,
|
||||
session: Arc<SessionTaskContext>,
|
||||
|
||||
@@ -31,6 +31,10 @@ impl SessionTask for UndoTask {
|
||||
TaskKind::Regular
|
||||
}
|
||||
|
||||
fn span_name(&self) -> &'static str {
|
||||
"session_task.undo"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
self: Arc<Self>,
|
||||
session: Arc<SessionTaskContext>,
|
||||
|
||||
@@ -66,6 +66,10 @@ impl SessionTask for UserShellCommandTask {
|
||||
TaskKind::Regular
|
||||
}
|
||||
|
||||
fn span_name(&self) -> &'static str {
|
||||
"session_task.user_shell"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
self: Arc<Self>,
|
||||
session: Arc<SessionTaskContext>,
|
||||
|
||||
Reference in New Issue
Block a user