Skip to content

feat(tools): add LoggingAspect to execute_tool dispatch#3

Open
yijunyu wants to merge 1 commit intoemmarktech:mainfrom
yijunyu:yijunyu/feat/aspect-rs-logging-on-tool-dispatch
Open

feat(tools): add LoggingAspect to execute_tool dispatch#3
yijunyu wants to merge 1 commit intoemmarktech:mainfrom
yijunyu:yijunyu/feat/aspect-rs-logging-on-tool-dispatch

Conversation

@yijunyu
Copy link
Copy Markdown

@yijunyu yijunyu commented Apr 23, 2026

Summary

Annotates pub fn execute_tool in rust/crates/tools/src/lib.rs — the single match dispatch every tool invocation flows through — with aspect_std::LoggingAspect, creating a structured audit trail for tool execution where none currently exists.

Adds four small deps (aspect-core, aspect-macros, aspect-std, log) to the tools crate. No behavioral change — aspect-rs weaves at compile time and this aspect is observation-only (entry/exit/error logging via the log facade).

Logical diff: +7 lines (+4 in Cargo.toml, +3 in lib.rs), plus Cargo.lock auto-update.

Why

A static scan of the Rust crates on current main turned up zero uses of tracing:: or log::. Every tool invocation, provider call, and hook currently emits either nothing or a raw println! / eprintln!. For an agent harness that runs bash, writes files, and calls third-party LLMs, this is a concrete observability gap.

This PR takes the smallest possible step: one annotation on the one function every tool already passes through. It:

  • Creates a uniform entry/exit/error audit log for all 20+ tool branches (bash, read_file, write_file, edit_file, glob_search, grep_search, WebFetch, WebSearch, Skill, Agent, ToolSearch, NotebookEdit, Sleep, Config, REPL, PowerShell, StructuredOutput, Brief, TodoWrite).
  • Uses the log facade so downstream consumers pick any subscriber (env_logger, simple_logger, tracing-log) without library-side lock-in.
  • Weaves at compile time via the aspect-rs proc-macro — no runtime dispatch cost.

Why an aspect, not scattered tracing::instrument

  • tracing::instrument would require either a pervasive tracing dep plus N call-site edits across the dispatch arms, or else manual wrapper boilerplate on every tool branch.
  • #[aspect(...)] is one annotation on the one dispatch function. Future aspects (auth, rate-limit, timing, circuit-breaker) stack on the same function without rewriting the body — this is the pattern aspect-rs is built for.

Test plan

  • cargo check -p tools — clean
  • cargo test -p tools --lib — 27 passed; 1 pre-existing failure (tests::skill_loads_local_skill_prompt — reproduces on unmodified main, unrelated to this change)
  • cargo clippy -p tools --no-deps — no new warnings (4 pre-existing clippy warnings at lines 1812/1813/1825/2868 + runtime/config.rs:510, all unrelated)
  • Reviewer manual: run with RUST_LOG=info and verify execute_tool entry/exit lines appear for every tool call
  • Reviewer manual: run with default (no RUST_LOG) and verify zero log emission (log facade fast-path)

Blast radius

  • Behavioral change: none. Aspect is observation-only; return values unchanged on success and failure.
  • Runtime cost: one log::log_enabled!() check per invocation when logging is filtered out; a formatted string emission when enabled. Tool invocations are already I/O-bound.
  • Surface area: one function. Revert is a 3-line git revert.

Context

This PR is part of a broader crosscutting-concerns study on Rust agent-harness codebases. Upstream ultraworkers/claw-code currently has external PRs disabled (viewerPermission: READ); this fork is the most suitable active target for the Rust variant. Full analysis with scattering/tangling tables is available on request.

Follow-ups (not in this PR)

Each of these is a similarly minimal ~10-line PR once this lands:

  1. LoggingAspect on api::ProviderClient::send_message
  2. Stack aspect_std::TimingAspect on both — performance instrumentation
  3. aspect_std::RateLimitAspect on provider calls — closes the producer-side rate-limiting gap (currently only reactive to 429s)
  4. aspect_std::CircuitBreakerAspect on provider calls — replaces ad-hoc retry loops in api/providers/anthropic.rs

References

Every tool invocation flows through execute_tool; annotating it with
aspect_std::LoggingAspect creates a structured audit trail for the
entire 20+ tool surface with one annotation.

No behavioral change. Uses the log facade so downstream consumers pick
the subscriber. Aspect weaving happens at compile time via the aspect-rs
proc-macro -- zero runtime cost.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant