trace() Context Manager
Create sub-spans inline with neatlogs.trace().
with neatlogs.trace(...) creates a span for a block of code inside an existing function. Use it when you need to add a span within a function that is already decorated with @span, or when you need to track prompt templates on an LLM call.
When to Use trace()
- Prompt template tracking: wrap the
compile()+ LLM call to capture the template and variables in the span - Sub-spans inside
@spanfunctions: add granularity to a specific block without decorating a separate function - Grouping multiple top-level operations in a
main()or script
Do not use trace() just to "create a span" around framework code — auto-instrumentation handles that automatically.
Signature
with neatlogs.trace(
name,
kind=None,
prompt_template=None,
user_prompt_template=None,
version=None,
**attributes,
) as span:
...Prompt Template Tracking
The most common use of trace() is to link a prompt template to the LLM span it produces. Use kind="LLM" and place this at the smallest unit containing the LLM call:
from neatlogs import PromptTemplate, UserPromptTemplate
system_template = PromptTemplate([
{"role": "system", "content": "You are a {{role}} assistant."},
])
user_template = UserPromptTemplate([
{"role": "user", "content": "{{question}}"},
])
@neatlogs.span(kind="AGENT")
def answer_agent(question: str) -> str:
with neatlogs.trace("answer_prompt", kind="LLM",
prompt_template=system_template,
user_prompt_template=user_template):
system_msgs = system_template.compile(role="support")
user_msgs = user_template.compile(question=question)
response = openai_client.chat.completions.create(
model="gpt-4o",
messages=system_msgs + user_msgs,
)
return response.choices[0].message.contentSub-span Inside a Function
Add a retriever or reranker sub-span inside a chain or agent function:
import json
import neatlogs
@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))
# ... generate answer ...Grouping Multiple Top-Level Operations
In a script or main() where you have multiple top-level steps that aren't inside a @span function, wrap them together:
def main():
with neatlogs.trace("data_pipeline"):
data = fetch_data("api")
result = process_data(data)
output = generate_report(result)Setting Custom Attributes
The span object returned by the context manager is a standard OpenTelemetry span:
with neatlogs.trace("my_step", kind="RETRIEVER") as span:
span.set_attribute("neatlogs.retrieval.query", query)
span.set_attribute("neatlogs.retrieval.top_k", 5)
docs = retriever.search(query)
span.set_attribute("neatlogs.retrieval.documents", json.dumps(docs))See Custom Attributes for all available neatlogs.* attribute names.