Structured tracing for LLM applications. JSONL files, hierarchical spans, zero infrastructure.
Project description
traqo
Structured tracing for LLM applications. JSONL files, hierarchical spans, zero infrastructure.
from traqo import Tracer, trace
from pathlib import Path
@trace()
async def classify(text: str) -> str:
response = await llm.chat(text)
return response
with Tracer(Path("traces/run.jsonl")):
await classify("Is this a bug?")
Your traces are just .jsonl files. Read them with grep, query them with DuckDB, or hand them to an AI assistant.
Why traqo?
- Zero infrastructure -- no server, no database, no account.
pip install traqoand go. - AI-first -- JSONL is text. AI assistants read your traces directly, no browser needed.
- Hierarchical spans -- not flat logs. Reconstruct the full call tree across functions and files.
- Zero dependencies -- stdlib only. Integrations are optional extras.
- Transparent -- traces are portable files. No vendor lock-in, no proprietary format.
Install
pip install traqo # Core (zero dependencies)
pip install traqo[openai] # + OpenAI integration
pip install traqo[anthropic] # + Anthropic integration
pip install traqo[langchain] # + LangChain integration
pip install traqo[all] # Everything
Quick Start
1. Trace a function
from traqo import Tracer, trace
from pathlib import Path
@trace()
async def summarize(text: str) -> str:
# your logic here
return summary
@trace()
async def pipeline(docs: list[str]) -> list[str]:
return [await summarize(doc) for doc in docs]
async with Tracer(Path("traces/my_run.jsonl")):
results = await pipeline(["doc1", "doc2"])
2. Auto-trace LLM calls
from traqo.integrations.openai import traced_openai
from openai import OpenAI
client = traced_openai(OpenAI(), operation="summarize")
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Summarize this..."}],
)
# Token usage, duration, input/output all captured automatically
Works the same way for Anthropic and LangChain:
from traqo.integrations.anthropic import traced_anthropic
from traqo.integrations.langchain import traced_model
3. Read your traces
# Last line is always trace_end with summary stats
tail -1 traces/my_run.jsonl | jq .
# All LLM calls
grep '"type":"llm_call"' traces/my_run.jsonl | jq .
# Errors
grep '"status":"error"' traces/**/*.jsonl
# Token costs
grep '"type":"llm_call"' traces/**/*.jsonl | jq '.token_usage'
API Reference
Tracer(path, *, metadata=None, capture_content=True)
Creates a trace session writing to a JSONL file. Use as a context manager.
with Tracer(
Path("traces/run.jsonl"),
metadata={"run_id": "abc123", "model": "gpt-4o"},
capture_content=False, # Omit LLM input/output (keep tokens, duration)
):
await my_pipeline()
| Parameter | Type | Default | Description |
|---|---|---|---|
path |
Path |
required | JSONL file path. Parent dirs created automatically. |
metadata |
dict |
{} |
Arbitrary metadata written to trace_start. |
capture_content |
bool |
True |
If False, LLM inputs/outputs omitted. |
Methods:
| Method | Description |
|---|---|
log(name, data) |
Write a custom event |
llm_event(model=, input_messages=, output_text=, token_usage=, duration_s=, operation=) |
Write an llm_call event |
span(name, inputs) |
Manual span context manager |
child(name, path) |
Create a child tracer writing to a separate file |
@trace(name=None, *, capture_input=True, capture_output=True)
Decorator that wraps a function in a span. Works with sync and async functions.
@trace()
async def my_step(data: list) -> dict:
return process(data)
@trace("custom_name", capture_input=False)
def sensitive_step(secret: str) -> str:
return handle(secret)
When no tracer is active, @trace is a pure passthrough with zero overhead.
get_tracer() -> Tracer | None
Returns the active tracer for the current context, or None.
from traqo import get_tracer
tracer = get_tracer()
if tracer:
tracer.log("checkpoint", {"count": len(results)})
disable() / enable()
import traqo
traqo.disable() # All tracing becomes no-op
traqo.enable() # Re-enable
Or via environment variable: TRAQO_DISABLED=1
Child Tracers
For concurrent agents or workers that produce many events. Each child writes to its own file, linked to the parent.
with Tracer(Path("traces/pipeline.jsonl")) as tracer:
child = tracer.child("reentrancy_agent", Path("traces/agents/reentrancy.jsonl"))
with child:
await run_agent(...)
The parent trace records child_started / child_ended events and includes child summaries in trace_end.
JSONL Format
Every line is a self-contained JSON object. Six event types:
| Type | When | Key Fields |
|---|---|---|
trace_start |
Tracer enters | tracer_version, metadata |
span_start |
Function/span begins | id, parent_id, name, input |
span_end |
Function/span ends | id, duration_s, status, output, error |
llm_call |
LLM invocation | model, input, output, token_usage, duration_s |
event |
Custom checkpoint | name, data |
trace_end |
Tracer exits | duration_s, stats, children |
Query with DuckDB
SELECT model, count(*) as calls,
sum(token_usage.input_tokens) as total_in,
sum(token_usage.output_tokens) as total_out,
avg(duration_s) as avg_duration
FROM read_json('traces/**/*.jsonl')
WHERE type = 'llm_call'
GROUP BY model;
vs Alternatives
| Dimension | traqo | Opik (self-hosted) | Langfuse (self-hosted) |
|---|---|---|---|
| Infrastructure | None (filesystem) | Docker + ClickHouse + MySQL | Docker + Postgres |
| Setup | pip install traqo |
Docker compose + config | Docker compose + config |
| Monthly cost | $0 | $50-200 | $50-200 |
| Data format | JSONL (portable) | ClickHouse tables | Postgres tables |
| Query method | grep / DuckDB / AI | SQL + UI | SQL + UI |
| Dependencies | Zero | Many | Many |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file traqo-0.1.0.tar.gz.
File metadata
- Download URL: traqo-0.1.0.tar.gz
- Upload date:
- Size: 94.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ca900b685064180a796fde76d16eee99fee6287d6f64de1ab13f13a15a74373
|
|
| MD5 |
dba2058145bc93d710af797f0ea9035d
|
|
| BLAKE2b-256 |
f3eec98a17c4f51d869d60879042eeaf6b9ed0fbf8b3655058896728bb64078c
|
Provenance
The following attestation bundles were made for traqo-0.1.0.tar.gz:
Publisher:
publish.yml on Cecuro/traqo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
traqo-0.1.0.tar.gz -
Subject digest:
6ca900b685064180a796fde76d16eee99fee6287d6f64de1ab13f13a15a74373 - Sigstore transparency entry: 973638968
- Sigstore integration time:
-
Permalink:
Cecuro/traqo@2f2d18e529ae4f23870f89c0cb514f981106af44 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Cecuro
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2f2d18e529ae4f23870f89c0cb514f981106af44 -
Trigger Event:
release
-
Statement type:
File details
Details for the file traqo-0.1.0-py3-none-any.whl.
File metadata
- Download URL: traqo-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1621c85d15bbd95ee052c7c8f96c932f3d2c80650d88f089a6e256074da29a6
|
|
| MD5 |
7f0e56917590c0863547d01d3be67d9e
|
|
| BLAKE2b-256 |
c0021920098e7d146811270cfced009e5eff6b30d5cee2bfca74936eda84b101
|
Provenance
The following attestation bundles were made for traqo-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Cecuro/traqo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
traqo-0.1.0-py3-none-any.whl -
Subject digest:
e1621c85d15bbd95ee052c7c8f96c932f3d2c80650d88f089a6e256074da29a6 - Sigstore transparency entry: 973638978
- Sigstore integration time:
-
Permalink:
Cecuro/traqo@2f2d18e529ae4f23870f89c0cb514f981106af44 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Cecuro
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2f2d18e529ae4f23870f89c0cb514f981106af44 -
Trigger Event:
release
-
Statement type: