11"""Step definitions for telemetry.feature."""
22
3+ import logging
34import os
45
56from langchain_core .messages import HumanMessage
1617)
1718from ._agent import build_langgraph_agent
1819
20+ log = logging .getLogger (__name__ )
21+
1922# --- scenario bindings ---
2023
2124
@@ -99,22 +102,22 @@ def set_baggage(key, value):
99102def invoke_agent_full (provider , name , cid , memory_exporter , span_store ):
100103 with invoke_agent_span (provider = provider , agent_name = name , conversation_id = cid ):
101104 pass
102- span_store ["last" ] = _find_span (memory_exporter , f"invoke_agent { name } " )
105+ span_store ["last" ] = _require_span (memory_exporter , f"invoke_agent { name } " )
103106
104107
105108@when ("I invoke an agent that raises an exception" )
106109def invoke_agent_with_error (memory_exporter , span_store ):
107110 with pytest .raises (RuntimeError ):
108111 with invoke_agent_span (provider = "test" , agent_name = "error-agent" ):
109112 raise RuntimeError ("deliberate test error" )
110- span_store ["last" ] = _find_span (memory_exporter , "invoke_agent error-agent" )
113+ span_store ["last" ] = _require_span (memory_exporter , "invoke_agent error-agent" )
111114
112115
113116@when (parsers .parse ('I invoke an agent with provider "{provider}" and name "{name}"' ))
114117def invoke_agent_named (provider , name , memory_exporter , span_store ):
115118 with invoke_agent_span (provider = provider , agent_name = name ):
116119 pass
117- span_store ["last" ] = _find_span (memory_exporter , f"invoke_agent { name } " )
120+ span_store ["last" ] = _require_span (memory_exporter , f"invoke_agent { name } " )
118121
119122
120123def _llm_call ():
@@ -134,7 +137,9 @@ def _llm_call():
134137def invoke_agent_wrapping_llm (memory_exporter , transforming_exporter , span_store ):
135138 with invoke_agent_span (provider = "sap-aicore" , agent_name = "llm-agent" ):
136139 _llm_call ()
137- span_store ["all_local_spans" ] = transforming_exporter .get_finished_spans ()
140+ spans = transforming_exporter .get_finished_spans ()
141+ _log_spans (spans )
142+ span_store ["all_local_spans" ] = spans
138143
139144
140145@when ("I invoke an agent that calls an LLM then executes a tool" )
@@ -143,7 +148,9 @@ def invoke_agent_llm_then_tool(memory_exporter, transforming_exporter, span_stor
143148 _llm_call ()
144149 with execute_tool_span (tool_name = "search" , tool_type = "function" ):
145150 pass
146- span_store ["all_local_spans" ] = transforming_exporter .get_finished_spans ()
151+ spans = transforming_exporter .get_finished_spans ()
152+ _log_spans (spans )
153+ span_store ["all_local_spans" ] = spans
147154
148155
149156@when ("I invoke an agent with propagate=True wrapping a real LLM call" )
@@ -155,7 +162,9 @@ def invoke_agent_propagate_to_llm(memory_exporter, transforming_exporter, span_s
155162 propagate = True ,
156163 ):
157164 _llm_call ()
158- span_store ["all_local_spans" ] = transforming_exporter .get_finished_spans ()
165+ spans = transforming_exporter .get_finished_spans ()
166+ _log_spans (spans )
167+ span_store ["all_local_spans" ] = spans
159168
160169
161170@when ("I invoke an agent with propagate=False wrapping a real LLM call" )
@@ -167,14 +176,18 @@ def invoke_agent_no_propagate_to_llm(memory_exporter, transforming_exporter, spa
167176 propagate = False ,
168177 ):
169178 _llm_call ()
170- span_store ["all_local_spans" ] = transforming_exporter .get_finished_spans ()
179+ spans = transforming_exporter .get_finished_spans ()
180+ _log_spans (spans )
181+ span_store ["all_local_spans" ] = spans
171182
172183
173184@when ("I invoke an agent wrapping a direct LLM call with baggage" )
174185def invoke_agent_wrapping_llm_with_baggage (memory_exporter , transforming_exporter , span_store ):
175186 with invoke_agent_span (provider = "sap-aicore" , agent_name = "baggage-llm-agent" ):
176187 _llm_call ()
177- span_store ["all_local_spans" ] = transforming_exporter .get_finished_spans ()
188+ spans = transforming_exporter .get_finished_spans ()
189+ _log_spans (spans )
190+ span_store ["all_local_spans" ] = spans
178191
179192
180193@when (parsers .parse ('I run a LangGraph agent with provider "{provider}" and name "{name}"' ))
@@ -184,8 +197,9 @@ def run_langgraph_agent(provider, name, transforming_exporter, span_store):
184197 span_store ["root_span_id" ] = root_span .get_span_context ().span_id
185198 agent .invoke ({"messages" : [HumanMessage (content = "Say hello in one word." )]})
186199 all_spans = transforming_exporter .get_finished_spans ()
200+ _log_spans (all_spans )
187201 span_store ["all_spans" ] = all_spans
188- span_store ["last" ] = _find_span_in (all_spans , f"invoke_agent { name } " )
202+ span_store ["last" ] = _require_span_in (all_spans , f"invoke_agent { name } " )
189203
190204
191205# --- then steps ---
@@ -357,10 +371,30 @@ def _find_span(exporter: InMemorySpanExporter, name: str) -> ReadableSpan | None
357371 return _find_span_in (exporter .get_finished_spans (), name )
358372
359373
374+ def _require_span (exporter : InMemorySpanExporter , name : str ) -> ReadableSpan :
375+ spans = exporter .get_finished_spans ()
376+ return _require_span_in (spans , name )
377+
378+
360379def _find_span_in (spans : list [ReadableSpan ], name : str ) -> ReadableSpan | None :
361380 return next ((s for s in spans if s .name == name ), None )
362381
363382
383+ def _require_span_in (spans : list [ReadableSpan ], name : str ) -> ReadableSpan :
384+ span = _find_span_in (spans , name )
385+ assert span is not None , (
386+ f"No span named '{ name } ' found.\n "
387+ f"Recorded spans: { [s .name for s in spans ]} "
388+ )
389+ return span
390+
391+
392+ def _log_spans (spans : list [ReadableSpan ]) -> None :
393+ log .info ("Collected %d span(s):" , len (spans ))
394+ for s in spans :
395+ log .info (" [%s] attrs=%s" , s .name , dict (s .attributes or {}))
396+
397+
364398def _get_descendants (all_spans : list [ReadableSpan ], root_span_id : int ) -> list [ReadableSpan ]:
365399 return [
366400 s for s in all_spans
0 commit comments