Lightweight span-based tracing for LangChain/LangGraph agents
Project description
gtracer
Lightweight span-based tracing for LangChain and LangGraph agents.
Emits structured JSONL spans via Python's standard logging —
no new infrastructure, no agents, no dashboards required.
What it does
Every time an LLM call happens inside your agent, gtracer captures it as a structured span and writes it to stdout as JSON:
run
└── agent "main"
├── llm_call seq:1 ← tokens, model, message delta, latency
│ └── tool_call search_database ← input, result, duration
├── llm_call seq:2
│ └── tool_call calculator
└── llm_call seq:3 ← final answer
Works with CloudWatch, Datadog, or any stdout log consumer. Zero configuration — spans are live the moment you import the package.
Install
pip install gtracer
# or
uv add gtracer
Quick Start
1. Import and go
import gtracer # spans are live immediately — nothing else needed
gtracer auto-configures at import time. It attaches its own JSON handler with propagate=False — it never touches your app's root logger, no double-emission, no interference.
2. Wrap your agent
from gtracer import tracer, tracing_handler
async def run(session_id: str, user_input: str):
tracer.start_trace(session_id)
with tracer.span("run", tags={"session_id": session_id}):
with tracer.span("agent", attrs={"agent": "main"}) as agent_span:
result = await my_agent.ainvoke(
{"messages": [{"role": "user", "content": user_input}]},
config={"callbacks": [tracing_handler]},
)
agent_span.set("output_type", type(result).__name__)
return result
Every LLM call is now automatically captured — tokens, model, latency, message deltas.
3. Instrument your tools
from langchain_core.tools import tool
from gtracer import tracer, tracing_handler, _span_id
@tool
async def search_database(query: str) -> str:
"""Run a database query."""
llm_parent = tracing_handler.last_llm_span(_span_id.get())
with tracer.span("tool_call",
attrs={"tool": "search_database", "input": {"query": query}},
parent_span_id=llm_parent) as span:
result = await execute_query(query)
span.set("result", result)
return result
Silence in Production
Set the env var — no code change needed:
GTRACER_ENABLED=false
Tracing mechanics (spans, callbacks, token counts) stay fully active. Only stdout output is suppressed.
Span Schema
Every span event is a flat JSON object on a single line:
{
"ts": "2026-03-30T10:00:00",
"level": "TRACE",
"event": "span.end",
"span_name": "llm_call",
"trace_id": "abc123",
"span_id": "a1b2c3d4",
"parent_span_id": "e5f6a7b8",
"status": "ok",
"duration_ms": 1823,
"attrs": {
"agent": "main",
"model": "claude-sonnet-4-6",
"seq": 2,
"tokens": {
"input": 461,
"output": 277,
"total": 738,
"input_cache_read": 15541
},
"stop_reason": "tool_use"
}
}
Each llm_call span captures:
| Field | Description |
|---|---|
attrs.tokens |
input, output, total, cache_read, cache_creation |
attrs.model |
exact model ID from the provider response |
attrs.delta |
new messages added since the previous LLM call |
duration_ms |
wall-clock latency in milliseconds |
attrs.stop_reason |
tool_use, end_turn, etc. |
Configuration
from gtracer import configure
configure(truncation_limit=50_000) # max chars for message content fields (default)
Supported Patterns
| Pattern | Description |
|---|---|
create_agent |
ReAct loop with tool use and structured output |
StateGraph |
LangGraph graphs with custom nodes |
| Nested agents | Agent-as-a-tool with causal span parenting |
| Deep Agents | LangChain create_deep_agent with sub-agents |
| Parallel tools | Concurrent tool calls under the same llm_call parent |
See docs/documentation.md for full integration patterns, API reference, and gotchas.
Requirements
Project details
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 gtracer-0.1.2.tar.gz.
File metadata
- Download URL: gtracer-0.1.2.tar.gz
- Upload date:
- Size: 11.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eab9441a4edce6413ba5fe9e62c3bfa7fbbd7f9a602af14102970a696a97d4d5
|
|
| MD5 |
6a10bf5372111c0736b9b6751e75bb3d
|
|
| BLAKE2b-256 |
bb1e3a0b1d171d4d8e1079cfeb2d5d6ce4c50d24cde2eaeb2315ad251d37d229
|
File details
Details for the file gtracer-0.1.2-py3-none-any.whl.
File metadata
- Download URL: gtracer-0.1.2-py3-none-any.whl
- Upload date:
- Size: 13.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22365ff7730956a286c20982cacd55457890d23bf35f2782c0df2b2993e066b3
|
|
| MD5 |
6e0e5110a2c6471225ba09c134c25273
|
|
| BLAKE2b-256 |
d56795a521df85b00bb01118b824efaa24d414653540451bece52c5f9790d97a
|