Use manual tracing when you need explicit control over what gets logged and when.
How it works
- Create one
NexusClient per request or workflow.
- Create nested spans with
client.span(...).
- Set outputs or errors on spans.
- Call
client.flush() to persist buffered events.
Minimal example
from uuid import uuid4
from nexus_library.nexus_core import NexusClient
client = NexusClient(api_key=str(uuid4()), db_url="postgresql://user:pass@host/db")
with client.span("orchestrator", event_type="chain", input_data={"task": "summarize"}) as root:
with client.span("retrieve-docs", event_type="retriever", input_data={"k": 5}) as retrieve_span:
retrieve_span.set_output({"hits": 5})
with client.span("generate-answer", event_type="llm", input_data={"model": "gpt-4.1"}) as llm_span:
llm_span.set_output({"text": "Final answer"})
root.set_output({"status": "ok"})
client.flush()
Span behavior
- A span gets a generated
run_id.
- The active parent span becomes
parent_run_id for children.
- Exceptions inside
with client.span(...) mark the span as errored.
- Exceptions are re-raised after logging because span context managers do not suppress them.
Choosing event_type
Use categories that map to your architecture:
chain
llm
chat_model
tool
agent
retriever
text
retry
Common pitfalls
NexusClient(api_key=...) converts strings into uuid.UUID. If your API key is not UUID-formatted, initialization fails.
- Forgetting to call
flush() means events stay in memory.
- Passing non-JSON-serializable objects is allowed, but they are converted to strings.