Python SDK
Manual spans
st.span is for when decorators are too coarse — sub-steps, conditional tracing, anything you need to mutate while it runs.
with st.span("embed-query", kind="retriever") as s:
s.metadata["query"] = query
result = embed(query)
s.metadata["hit_count"] = len(result)Signature
st.span(name: str, *, kind: str | SpanKind = SpanKind.CHAIN) -> ContextManager[Span]Valid kind: "llm", "tool", "chain", "retriever", "agent", "custom".
Methods
| Purpose | |
|---|---|
s.metadata[key] = value | Attach metadata. |
s.input = {...} | Record a custom input payload. |
s.output = {...} | Record a custom output payload. |
s.annotate(name, value=..., data_type=...) | Attach a score or label. See annotations. |
s.set_status(status, description=None) | Force ok, error, or timeout. |
s.record_exception(exc) | Mark errored and record the exception. |
Exceptions raised inside the with block are recorded automatically. Use record_exception only when you catch the exception and still want it logged.
with st.span("call-stripe", kind="tool") as s:
try:
charge = stripe.charge(...)
s.output = {"charge_id": charge.id}
except stripe.error.CardError as exc:
s.record_exception(exc)
s.set_status("error", "card declined")
raiseDecorators vs manual
| Decorators | Manual spans |
|---|---|
| Whole function. | Block inside a function. |
| Inputs/outputs match arguments. | Mutate fields mid-execution. |
| One unit per function. | Conditional tracing. |
They compose freely.