Tracer instance to defineAgent and every request handled by that route is automatically instrumented, with no changes required inside individual handlers or tools.
Stores: where traces live
Anvil ships twoTraceStore implementations. Choose one based on your environment.
MemoryTraceStore
Zero-dependency in-memory store. Traces survive only for the lifetime of the process — ideal for unit tests and local experimentation where you don’t need a database.
SqliteTraceStore
SQLite-backed store powered by
better-sqlite3 (optional peer dependency). Persists traces across restarts. The recommended default for production. Default path: .anvil/traces.db.MemoryTraceStore
store.clear() between test cases to reset state.
SqliteTraceStore
SqliteTraceStore.open creates the file and schema on first call. Pass ':memory:' for a process-scoped SQLite database that behaves like MemoryTraceStore but uses the same SQL interface.
better-sqlite3 is an optional peer dependency. Install it before using SqliteTraceStore:Creating a Tracer
Tracer wraps a TraceStore and optionally accepts an onExport hook that fires when each trace ends — this is the seam used by the OpenTelemetry exporter.
TracerOptions accepts one field:
Callback invoked with the completed
Trace after traceHandle.end() is called. Use this to pipe traces to an external system without coupling your store to the export logic.Wiring the Tracer into defineAgent
Pass thetracer as an option to defineAgent. Anvil opens one TraceHandle per incoming request and closes it when the response stream ends.
Naming traces
By default, Anvil names each traceagent <route-path>. Override this with traceName:
- Static string
- Dynamic from context
The Trace and Span types
Every finished trace is aTrace object containing a flat list of Span records that form a tree via parentId references.
Trace
Span
SpanKind identifies what produced the span:
| Kind | Description |
|---|---|
agent | The top-level agent loop span |
model | A single LLM generate call, including usage and cost |
tool | One tool execution |
retrieval | A ctx.retrieve() call |
cache | A semantic cache hit or miss |
judge | An LLM-as-judge evaluation |
http | An outbound HTTP call |
Retrieval spans from
ctx.retrieve() are recorded in the same trace tree as the agent run. They appear as kind: 'retrieval' children of the enclosing agent span, so you can see the full RAG context alongside model calls in one view.TraceStore interface
If you need a custom backend (Redis, Postgres, etc.) implementTraceStore directly:
ListTracesOptions accepts limit and offset for pagination.
Full example
/_anvil in the browser to inspect the span tree, token usage, and cost in real time.