ragleap-trace
version — loading live from PyPI…
Status: first release (0.1.0). A small tracing library, standard library only. It records spans in your own process and writes them to memory or to a local file. There are no network exporters.
pip install ragleap-trace
Python 3.10 or newer. No runtime dependencies (standard library only).
Highlights
- Spans with a
Tracer, a context manager and a@traceddecorator for sync and async code, two exporters (InMemoryExporterandJsonlExporter), andTracer.record()for spans that already finished - Privacy by default: only the exception class name is recorded, never its message; only
str,int,floatandboolattribute values are kept (objects are dropped, never printed); keys such asprompt,answer,query,file_name,passwordandtokenare never recorded - Hard limits: name 128, key 64, 32 attributes per span, strings cut at 256 characters. Dropped attributes are counted in
dropped_attributes - Tracing does not break your application: a span is recorded even when the body raises, and the exception still propagates unchanged. Exporter errors never reach your code; they are counted in
tracer.dropped JsonlExportercreates files with mode 0600 and refuses an existing file that group or others can read- An adapter for ragleap-rag,
RagTraceAdapter, turns itson_ingest,on_queryandon_answerhooks into spans (rag.ingest,rag.query,rag.answer). It copies only an allow-list: counts, booleans, the provider name, token numbers and the query length. Query text, answer text and file names are never copied
Try it (copied from the README at the 0.1.0 tag)
from ragleap_trace import Tracer, JsonlExporter, traced
tracer = Tracer([JsonlExporter("traces.jsonl")])
with tracer.span("retrieve", top_k=5) as s:
s.set_attribute("hits", 4)
@traced(tracer)
async def answer(...): ...
from ragleap_trace import Tracer, JsonlExporter, RagTraceAdapter
tracer = Tracer([JsonlExporter("traces.jsonl")])
adapter = RagTraceAdapter(tracer)
hooks = adapter.hooks() # lists keyed on_ingest / on_query / on_answer
Measurements and limits
Our Tests page lists 2 test files and 47 test functions on the main branch (counted from the repository, not a pass count). The changelog records, as separate measures: the core 34 tests and 24 of 24 deliberate breaks caught, on the VPS (Python 3.10.12) and in CI on 3.10 and 3.12; the adapter 63 tests and 42 of 42 breaks, same environments; and 9 integration tests and 12 of 12 breaks against a real RagLeap (Postgres 16 with pgvector, a fake embedder and a fake generator), in CI on Python 3.11. Not verified, as the changelog says: real LLM providers, vector backends other than pgvector, spans handed between threads and Windows file permissions.
What it does not do
The key denylist is defense in depth, not a guarantee: a value under an innocent key is recorded as you give it, so do not put secrets or personal data in attributes. There is no retention or rotation: the JSONL file grows until you remove it, and it is not encrypted. There is no opt-in content capture, no sampling, no network exporter and no multi-tenant tagging. Exporters run in the caller’s thread, so a slow exporter slows the caller (no timeout, no background queue). Events from ragleap-rag are paired per thread and per asyncio task, so two streams interleaved in one thread or task can pair an answer with the wrong query.