From 38211a3ff8e99a908257f34eb1fe9cd802fce501 Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Wed, 17 Jun 2026 14:53:54 -0700 Subject: [PATCH] [codex] trace tools build latency (#28782) Add more tracing spans around tool building. --- codex-rs/core-plugins/src/manager.rs | 9 +++++++ codex-rs/core-plugins/src/remote.rs | 2 ++ codex-rs/core/src/connectors.rs | 1 + .../core/src/tools/handlers/tool_search.rs | 7 ++++++ codex-rs/core/src/tools/registry.rs | 2 ++ codex-rs/core/src/tools/router.rs | 1 + codex-rs/core/src/tools/spec_plan.rs | 24 +++++++++++++++++++ codex-rs/login/src/auth/manager.rs | 2 ++ 8 files changed, 48 insertions(+) diff --git a/codex-rs/core-plugins/src/manager.rs b/codex-rs/core-plugins/src/manager.rs index 88b6cd3bb..fb004f494 100644 --- a/codex-rs/core-plugins/src/manager.rs +++ b/codex-rs/core-plugins/src/manager.rs @@ -942,6 +942,14 @@ impl PluginsManager { Ok(featured_plugin_ids) } + #[instrument( + level = "trace", + skip_all, + fields( + plugins_enabled = config.plugins_enabled, + remote_plugin_enabled = config.remote_plugin_enabled + ) + )] pub async fn recommended_plugins_mode_for_config( &self, config: &PluginsConfigInput, @@ -1014,6 +1022,7 @@ impl PluginsManager { /// Returns endpoint recommendations eligible for installation in the current client. /// `None` selects the legacy discovery workflow. + #[instrument(level = "trace", skip_all)] pub async fn recommended_plugin_candidates_for_config( &self, input: RecommendedPluginCandidatesInput<'_>, diff --git a/codex-rs/core-plugins/src/remote.rs b/codex-rs/core-plugins/src/remote.rs index 1f8d3f720..a0007aa1d 100644 --- a/codex-rs/core-plugins/src/remote.rs +++ b/codex-rs/core-plugins/src/remote.rs @@ -27,6 +27,7 @@ use std::fs; use std::path::Path; use std::path::PathBuf; use std::time::Duration; +use tracing::instrument; use url::Url; mod catalog_cache; @@ -805,6 +806,7 @@ pub async fn fetch_and_cache_global_remote_plugin_catalog( Ok(()) } +#[instrument(level = "trace", skip_all)] pub async fn fetch_recommended_plugins( config: &RemotePluginServiceConfig, auth: Option<&CodexAuth>, diff --git a/codex-rs/core/src/connectors.rs b/codex-rs/core/src/connectors.rs index f1c8c5607..496f14e86 100644 --- a/codex-rs/core/src/connectors.rs +++ b/codex-rs/core/src/connectors.rs @@ -94,6 +94,7 @@ pub(crate) async fn list_accessible_and_enabled_connectors_from_manager( .collect() } +#[instrument(level = "trace", skip_all)] pub(crate) async fn list_tool_suggest_discoverable_tools_with_auth( config: &Config, plugins_manager: &PluginsManager, diff --git a/codex-rs/core/src/tools/handlers/tool_search.rs b/codex-rs/core/src/tools/handlers/tool_search.rs index 5c201388b..272da2f22 100644 --- a/codex-rs/core/src/tools/handlers/tool_search.rs +++ b/codex-rs/core/src/tools/handlers/tool_search.rs @@ -20,6 +20,7 @@ use codex_tools::ToolSpec; use codex_tools::coalesce_loadable_tool_specs; use std::sync::Arc; use std::sync::Mutex; +use tracing::instrument; pub struct ToolSearchHandler { search_infos: Vec, @@ -33,6 +34,7 @@ pub(crate) struct ToolSearchHandlerCache { } impl ToolSearchHandlerCache { + #[instrument(level = "trace", skip_all, fields(search_info_count = search_infos.len()))] pub(crate) fn get_or_build(&self, search_infos: Vec) -> Arc { { let cached = self.cached(); @@ -64,6 +66,11 @@ impl ToolSearchHandlerCache { } impl ToolSearchHandler { + #[instrument( + level = "trace", + skip_all, + fields(search_info_count = search_infos.len()) + )] pub(crate) fn new(search_infos: Vec) -> Self { let search_source_infos = search_infos .iter() diff --git a/codex-rs/core/src/tools/registry.rs b/codex-rs/core/src/tools/registry.rs index 23294e694..2220d4244 100644 --- a/codex-rs/core/src/tools/registry.rs +++ b/codex-rs/core/src/tools/registry.rs @@ -34,6 +34,7 @@ use codex_tools::ToolSearchInfo; use codex_tools::ToolSpec; use futures::future::BoxFuture; use serde_json::Value; +use tracing::instrument; pub(crate) type ToolTelemetryTags = Vec<(&'static str, String)>; @@ -327,6 +328,7 @@ impl ToolRegistry { Self { tools } } + #[instrument(level = "trace", skip_all)] pub(crate) fn from_tools(tools: impl IntoIterator>) -> Self { let mut tools_by_name = HashMap::new(); for tool in tools { diff --git a/codex-rs/core/src/tools/router.rs b/codex-rs/core/src/tools/router.rs index 0acd6e37c..b48844839 100644 --- a/codex-rs/core/src/tools/router.rs +++ b/codex-rs/core/src/tools/router.rs @@ -240,6 +240,7 @@ impl ToolRouter { } } +#[instrument(level = "trace", skip_all)] pub(crate) fn extension_tool_executors( session: &Session, ) -> Vec>> { diff --git a/codex-rs/core/src/tools/spec_plan.rs b/codex-rs/core/src/tools/spec_plan.rs index 7680e5d4f..c697f287a 100644 --- a/codex-rs/core/src/tools/spec_plan.rs +++ b/codex-rs/core/src/tools/spec_plan.rs @@ -256,6 +256,7 @@ fn spec_for_model_request( } } +#[instrument(level = "trace", skip_all)] fn hosted_model_tool_specs(context: &CoreToolPlanContext<'_>) -> Vec { let turn_context = context.turn_context; // Responses Lite accepts schemas for client-executed tools, not hosted Responses tools. @@ -500,6 +501,7 @@ fn build_code_mode_executors( ] } +#[instrument(level = "trace", skip_all, fields(tool_spec_count = specs.len()))] fn merge_into_namespaces(specs: Vec) -> Vec { let mut merged_specs = Vec::with_capacity(specs.len()); let mut namespace_indices = BTreeMap::::new(); @@ -592,6 +594,7 @@ fn standalone_web_search_enabled(turn_context: &TurnContext) -> bool { .enabled(Feature::StandaloneWebSearch)) } +#[instrument(level = "trace", skip_all)] fn add_shell_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut PlannedTools) { let turn_context = context.turn_context; let features = turn_context.config.features.get(); @@ -643,6 +646,7 @@ fn unified_exec_should_include_shell_parameter(turn_context: &TurnContext) -> bo .any(|environment| environment.environment.is_remote()) } +#[instrument(level = "trace", skip_all)] fn add_mcp_resource_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut PlannedTools) { if context.mcp_tools.is_some() { planned_tools.add(ListMcpResourcesHandler); @@ -651,6 +655,7 @@ fn add_mcp_resource_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut } } +#[instrument(level = "trace", skip_all)] fn add_core_utility_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut PlannedTools) { let turn_context = context.turn_context; let features = turn_context.config.features.get(); @@ -722,6 +727,7 @@ fn add_core_utility_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut } } +#[instrument(level = "trace", skip_all)] fn add_collaboration_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut PlannedTools) { let turn_context = context.turn_context; if collab_tools_enabled(turn_context) { @@ -810,6 +816,14 @@ fn add_collaboration_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mu } } +#[instrument( + level = "trace", + skip_all, + fields( + direct_mcp_tool_count = context.mcp_tools.map_or(0, <[ToolInfo]>::len), + deferred_mcp_tool_count = context.deferred_mcp_tools.map_or(0, <[ToolInfo]>::len) + ) +)] fn add_mcp_runtime_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut PlannedTools) { if let Some(mcp_tools) = context.mcp_tools { for tool in mcp_tools { @@ -836,6 +850,11 @@ fn add_mcp_runtime_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut } } +#[instrument( + level = "trace", + skip_all, + fields(dynamic_tool_count = context.dynamic_tools.len()) +)] fn add_dynamic_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut PlannedTools) { for spec in context.dynamic_tools { match spec { @@ -868,6 +887,11 @@ fn add_dynamic_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut Plan } } +#[instrument( + level = "trace", + skip_all, + fields(extension_tool_executor_count = context.extension_tool_executors.len()) +)] fn add_extension_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut PlannedTools) { // Extension ToolContributor implementations are resolved into executors // before planning. Core only adapts those executors into its runtime set. diff --git a/codex-rs/login/src/auth/manager.rs b/codex-rs/login/src/auth/manager.rs index f4ed2a936..bb548ffe7 100644 --- a/codex-rs/login/src/auth/manager.rs +++ b/codex-rs/login/src/auth/manager.rs @@ -17,6 +17,7 @@ use std::sync::atomic::AtomicU64; use std::sync::atomic::Ordering; use tokio::sync::Semaphore; use tokio::sync::watch; +use tracing::instrument; use codex_agent_identity::ChatGptEnvironment; use codex_agent_identity::decode_agent_identity_jwt; @@ -1719,6 +1720,7 @@ impl AuthManager { /// Current cached auth (clone). May be `None` if not logged in or load failed. /// For managed ChatGPT auth that needs a proactive refresh, first performs /// a guarded reload and then refreshes only if the on-disk auth is unchanged. + #[instrument(level = "trace", skip_all)] pub async fn auth(&self) -> Option { if let Some(auth) = self.resolve_external_api_key_auth().await { return Some(auth);