trace hook command execution (#31501)

Adds a single trace span around configured hook command execution so
slow installed hooks are visible directly in traces.

The span records low-cardinality hook metadata and command outcome
without command text, hook input, stdout, or stderr.
This commit is contained in:
Tom authored and GitHub committed 2026-07-07 18:00:35 -07:00
1 parent 8784de445e
commit f8d07b5641
2 files changed
+159 -42

No files matched your search

+58 -2
View File
@@ -99,7 +99,7 @@ pub(crate) async fn execute_handlers<T>(
let input_json = input_json.clone();
let turn_id = turn_id.clone();
pending.push(async move {
let result = run_command(shell, &handler, &input_json, cwd).await;
let result = run_command(shell, &handler, configured_order, &input_json, cwd).await;
(configured_order, parse(&handler, result, turn_id))
});
}
@@ -139,7 +139,7 @@ pub(crate) fn completed_summary(
}
}
fn scope_for_event(event_name: HookEventName) -> HookScope {
pub(crate) fn scope_for_event(event_name: HookEventName) -> HookScope {
match event_name {
HookEventName::SessionStart | HookEventName::SubagentStart => HookScope::Thread,
HookEventName::PreToolUse
@@ -153,12 +153,68 @@ fn scope_for_event(event_name: HookEventName) -> HookScope {
}
}
pub(crate) fn hook_event_name_label(event_name: HookEventName) -> &'static str {
match event_name {
HookEventName::PreToolUse => "PreToolUse",
HookEventName::PermissionRequest => "PermissionRequest",
HookEventName::PostToolUse => "PostToolUse",
HookEventName::PreCompact => "PreCompact",
HookEventName::PostCompact => "PostCompact",
HookEventName::SessionStart => "SessionStart",
HookEventName::UserPromptSubmit => "UserPromptSubmit",
HookEventName::SubagentStart => "SubagentStart",
HookEventName::SubagentStop => "SubagentStop",
HookEventName::Stop => "Stop",
}
}
pub(crate) fn hook_execution_mode_label(mode: HookExecutionMode) -> &'static str {
match mode {
HookExecutionMode::Sync => "sync",
HookExecutionMode::Async => "async",
}
}
pub(crate) fn hook_handler_type_label(handler_type: HookHandlerType) -> &'static str {
match handler_type {
HookHandlerType::Command => "command",
HookHandlerType::Prompt => "prompt",
HookHandlerType::Agent => "agent",
}
}
pub(crate) fn hook_scope_label(scope: HookScope) -> &'static str {
match scope {
HookScope::Thread => "thread",
HookScope::Turn => "turn",
}
}
pub(crate) fn hook_source_label(source: codex_protocol::protocol::HookSource) -> &'static str {
match source {
codex_protocol::protocol::HookSource::System => "system",
codex_protocol::protocol::HookSource::User => "user",
codex_protocol::protocol::HookSource::Project => "project",
codex_protocol::protocol::HookSource::Mdm => "mdm",
codex_protocol::protocol::HookSource::SessionFlags => "session_flags",
codex_protocol::protocol::HookSource::Plugin => "plugin",
codex_protocol::protocol::HookSource::CloudRequirements => "cloud_requirements",
codex_protocol::protocol::HookSource::CloudManagedConfig => "cloud_managed_config",
codex_protocol::protocol::HookSource::LegacyManagedConfigFile => {
"legacy_managed_config_file"
}
codex_protocol::protocol::HookSource::LegacyManagedConfigMdm => "legacy_managed_config_mdm",
codex_protocol::protocol::HookSource::Unknown => "unknown",
}
}
#[cfg(test)]
mod tests {
use codex_protocol::protocol::HookEventName;
use codex_protocol::protocol::HookSource;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use pretty_assertions::assert_eq;
use super::ConfiguredHandler;
use super::select_handlers;