spring-projects / spring-projects/spring-ai

`DefaultAdvisorObservationConvention` produces a span name with stray spaces

Open Beginner friendly
#6,750 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage
Dominant language
Java
Stars
9.5k
Forks
2.9k
Avg merge
1d 7h
Merged PRs (30d)
6

Description

Bug description

The span produced for ToolCallingAdvisor is named tool _calling : there is a
space before _calling and a trailing space at the end. Tool calling is on by
default, so this appears in every trace where the model calls a tool.

Environment

Spring AI 2.0.0, Spring Boot 4.1.0, Java 21. Anthropic chat model with tool
callbacks supplied by an MCP client. Traces exported over OTLP to the
OpenTelemetry Collector. The same code is present on main.

Steps to reproduce
  1. Build a ChatClient with tool callbacks and tracing to an OTLP endpoint.
  2. Send a prompt that makes the model call a tool.
  3. Read the span names.

From the Collector's debug exporter, piped through cat -A so that $ marks
end of line:

Name           : tool _calling $
Name           : spring_ai chat_client$
Name           : call$
Expected behavior

A span name with no embedded or trailing whitespace, for example tool_calling.

Minimal Complete Reproducible example

https://github.com/kycasdzxc/spring-ai-otel-example

docker compose up -d, run the app, then ask a question that triggers a tool
call. The malformed name appears in the collector output and in Tempo.

The minimal condition is narrower than that project: any advisor whose
getName() returns a string containing spaces reproduces it. ToolCallingAdvisor
is built in, so no custom advisor is needed.

Root cause

DefaultAdvisorObservationConvention#getContextualName:

return ParsingUtils.reConcatenateCamelCase(context.getAdvisorName(), "_")
    .replace("_around_advisor", "")
    .replace("_advisor", "");

reConcatenateCamelCase splits on camelCase boundaries, so it expects an
identifier such as ToolCallingAdvisor. ToolCallingAdvisor#getName() returns
the display form "Tool Calling Advisor", and splitting that leaves the original
spaces attached to each token:

"Tool Calling Advisor"
  -> ["Tool ", "Calling ", "Advisor"]
  -> "tool _calling _advisor"
  -> replace("_advisor", "") -> "tool _calling "

Advisors whose name contains no spaces are unaffected: call stays call.

Either normalising whitespace in getContextualName or having advisors supply an
identifier-shaped name would fix it.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at DefaultAdvisorObservationConvention#getContextualName and inspect its use of ParsingUtils.reConcatenateCamelCase, with ToolCallingAdvisor as the reproduction path. Verify the resulting span name through the provided example or collector output; done means names such as tool_calling contain no embedded or trailing whitespace while unaffected names such as call remain valid.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring, spring-boot
Domain
observability
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.