fix: add is_recording() guards and use __qualname__ for error.type

Wrap attribute-setting blocks in server_span, delegate_span, and
client_span with `if span.is_recording():` to avoid unnecessary work
on non-recording spans. Use `type(e).__qualname__` instead of
`type(e).__name__` for the error.type attribute so nested/inner
exception classes get their fully qualified name.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
strawgate 2026-04-13 01:26:29 -05:00
commit f4694a99d6
2 changed files with 63 additions and 57 deletions

View file

@ -24,30 +24,32 @@ def client_span(
"""
tracer = get_tracer()
with tracer.start_as_current_span(name, kind=SpanKind.CLIENT) as span:
attrs: dict[str, str] = {
# MCP semantic conventions
"mcp.method.name": method,
# FastMCP-specific attributes
"fastmcp.component.key": component_key,
}
if session_id is not None:
attrs["mcp.session.id"] = session_id
if resource_uri:
attrs["mcp.resource.uri"] = resource_uri
if tool_name is not None:
attrs["gen_ai.tool.name"] = tool_name
if prompt_name is not None:
attrs["gen_ai.prompt.name"] = prompt_name
span.set_attributes(attrs)
if span.is_recording():
attrs: dict[str, str] = {
# MCP semantic conventions
"mcp.method.name": method,
# FastMCP-specific attributes
"fastmcp.component.key": component_key,
}
if session_id is not None:
attrs["mcp.session.id"] = session_id
if resource_uri:
attrs["mcp.resource.uri"] = resource_uri
if tool_name is not None:
attrs["gen_ai.tool.name"] = tool_name
if prompt_name is not None:
attrs["gen_ai.prompt.name"] = prompt_name
span.set_attributes(attrs)
try:
yield span
except Exception as e:
span.set_attribute(
"error.type",
"tool_error"
if type(e).__name__ == "ToolError"
else type(e).__name__,
)
if span.is_recording():
span.set_attribute(
"error.type",
"tool_error"
if type(e).__qualname__ == "ToolError"
else type(e).__qualname__,
)
span.record_exception(e)
span.set_status(Status(StatusCode.ERROR, str(e)))
raise

View file

@ -73,32 +73,34 @@ def server_span(
context=_get_parent_trace_context(),
kind=SpanKind.SERVER,
) as span:
attrs: dict[str, str] = {
# MCP semantic conventions
"mcp.method.name": method,
# FastMCP-specific attributes
"fastmcp.server.name": server_name,
"fastmcp.component.type": component_type,
"fastmcp.component.key": component_key,
**get_auth_span_attributes(),
**get_session_span_attributes(),
}
if resource_uri is not None:
attrs["mcp.resource.uri"] = resource_uri
if tool_name is not None:
attrs["gen_ai.tool.name"] = tool_name
if prompt_name is not None:
attrs["gen_ai.prompt.name"] = prompt_name
span.set_attributes(attrs)
if span.is_recording():
attrs: dict[str, str] = {
# MCP semantic conventions
"mcp.method.name": method,
# FastMCP-specific attributes
"fastmcp.server.name": server_name,
"fastmcp.component.type": component_type,
"fastmcp.component.key": component_key,
**get_auth_span_attributes(),
**get_session_span_attributes(),
}
if resource_uri is not None:
attrs["mcp.resource.uri"] = resource_uri
if tool_name is not None:
attrs["gen_ai.tool.name"] = tool_name
if prompt_name is not None:
attrs["gen_ai.prompt.name"] = prompt_name
span.set_attributes(attrs)
try:
yield span
except Exception as e:
span.set_attribute(
"error.type",
"tool_error"
if type(e).__name__ == "ToolError"
else type(e).__name__,
)
if span.is_recording():
span.set_attribute(
"error.type",
"tool_error"
if type(e).__qualname__ == "ToolError"
else type(e).__qualname__,
)
span.record_exception(e)
span.set_status(Status(StatusCode.ERROR, str(e)))
raise
@ -118,22 +120,24 @@ def delegate_span(
"""
tracer = get_tracer()
with tracer.start_as_current_span(f"delegate {name}") as span:
attrs: dict[str, str] = {
"fastmcp.provider.type": provider_type,
"fastmcp.component.key": component_key,
}
if method is not None:
attrs["mcp.method.name"] = method
span.set_attributes(attrs)
if span.is_recording():
attrs: dict[str, str] = {
"fastmcp.provider.type": provider_type,
"fastmcp.component.key": component_key,
}
if method is not None:
attrs["mcp.method.name"] = method
span.set_attributes(attrs)
try:
yield span
except Exception as e:
span.set_attribute(
"error.type",
"tool_error"
if type(e).__name__ == "ToolError"
else type(e).__name__,
)
if span.is_recording():
span.set_attribute(
"error.type",
"tool_error"
if type(e).__qualname__ == "ToolError"
else type(e).__qualname__,
)
span.record_exception(e)
span.set_status(Status(StatusCode.ERROR, str(e)))
raise