Logging Tool Calls and Inputs/Outputs
What to capture per step: tool name, input args, output, latency, error, and parent span id.
What to Log Per Step
For each span, capture:
- Step name (llm_call, tool_call, retrieve)
- Inputs (messages, tool args, query)
- Outputs (response, tool result)
- Metadata (model, latency, token counts, cost)
- Error info if failed
Hand-Rolled Span Helper
Without a framework, a minimal helper:
from contextlib import contextmanager
import time, uuid
@contextmanager
def span(name, trace_id, parent_id=None):
span_id = str(uuid.uuid4())
start = time.time()
record = {'trace_id': trace_id, 'span_id': span_id, 'parent_id': parent_id, 'name': name, 'start': start}
try:
yield record
except Exception as e:
record['error'] = str(e)
raise
finally:
record['duration_ms'] = (time.time() - start) * 1000
save_span(record)All lessons in this course
- Why You Need Tracing for Agents
- Logging Tool Calls and Inputs/Outputs
- Latency and Cost per Step
- Visualising Agent Runs (Langfuse, LangSmith)