Neatlogs
Quickstart

Instrument Your Own Code

Add spans to your own agents, pipelines, and tool functions.

Auto-instrumentation covers library calls — OpenAI, LangChain, ChromaDB, and the rest. Your own orchestration code is invisible to the tracer unless you add spans to it.

The primary way to do this is @neatlogs.span:

import neatlogs

@neatlogs.span(kind="WORKFLOW")
def handle_request(user_input: str) -> str:
    return support_agent(user_input)

@neatlogs.span(kind="AGENT", name="support_agent")
def support_agent(message: str) -> str:
    ...

@neatlogs.span(kind="TOOL", tool_name="get_order_status")
def get_order_status(order_id: str) -> dict:
    return orders_db.get(order_id)

This produces a trace like:

WORKFLOW  handle_request       0.8s
  AGENT   support_agent        0.8s
    LLM   gpt-4o               0.6s
    TOOL  get_order_status     0.0s

Every trace needs a WORKFLOW span at the root. Without one, spans from instrumented libraries float to the top with no parent. Wrap your entry point function and everything else nests under it automatically.

Span kinds

Pick the kind that matches what the function does:

KindUse for
WORKFLOWEntry point — one per trace root
AGENTA reasoning step that calls an LLM and decides what to do next
CHAINA fixed sequence of steps with no branching LLM decisions
TOOLA function the agent calls to interact with the world
RETRIEVERA vector search or document lookup
GUARDRAILA safety or validation check

When the kind matches the data the function returns (e.g. a RETRIEVER returning documents), the dashboard renders a specialized view for it automatically.

Inline spans with trace()

For a block inside an existing function, use the context manager instead of a decorator:

@neatlogs.span(kind="CHAIN")
def rag_pipeline(query: str) -> str:
    with neatlogs.trace("retrieve", kind="RETRIEVER") as span:
        span.set_attribute("neatlogs.retrieval.query", query)
        docs = my_retriever.search(query, k=5)
        span.set_attribute("neatlogs.retrieval.documents", json.dumps(docs))

    return generate(query, docs)

For the full decorator reference — all parameters, async support, disabling content capture — see @span Decorator.

For setting attributes manually on custom span kinds, see Custom Attributes.