Inference traces
Outside training there is no run and no policy step. A tracer anchored to the project alone records inference: each request becomes a trace owned by the project, and the portal and query SDK read them with no run named.
import metrana.tracing as tracing
tracing.init(workspace_name="my-team", project_name="agents", run_name=None) # project-anchored
def handle(messages): with tracing.model_trace("chat", prompt=messages, attributes={"model": "claude-y", "tier": "pro"}) as trace: reply = model(messages) trace.completion(reply.content) trace.token_count = reply.usage.total_tokens return reply
tracing.close() # at shutdownThe root is the model call
Section titled “The root is the model call”An inference trace that is one model call roots at an LLM_CALL node, and a root carries the bodies of its own
kind: model_trace takes the prompt on its open and trace.completion(...) on its close, exactly as an
llm_call span would. Tool calls the model made, retries and delegations nest beneath it as usual:
with tracing.model_trace("chat", prompt=messages) as trace: with tracing.tool_call("lookup", input={"doc": "report.pdf"}) as tool: tool.output(page) trace.completion(answer)A served agent, rather than a single call, roots at a SUB_AGENT with trace(name, kind=SpanKind.SUB_AGENT, input=task), whose input and output are the task and final output. A decorated request handler roots a FUNCTION
trace on its own:
@tracing.opdef handle(request: dict) -> dict: # top-level call, project-anchored: a trace with no step tracing.current_span().set_attributes({"route": request["path"]}) ...Anchoring is fixed per tracer
Section titled “Anchoring is fixed per tracer”Whether traces carry a step is the tracer’s, not the trace’s. A tracer built for a run requires step= (or a
tracing.step block) on every trace; one built for a project refuses it. The project must exist — a project is
created by its first run, or through the portal.
tracing.init(...) takes the same credentials and delivery settings as metrana.init (see
Configuration); its API key comes from METRANA_API_KEY like
everything else. In a process that also has a run open, run_name=None is what makes the tracer project-anchored
rather than the run’s.
Reading them back
Section titled “Reading them back”With no run, the query SDK’s runs= is left empty and run=None names the project’s own traces:
client.fetch_spans(filter=AttrFilter("tier") == "pro") # inference traces of the projectclient.fetch_span_payloads(trace_id, run=None) # prompt and completion on span 0See Searching traces.