RagLeap
PyPI package (first release)

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.

pypi license
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 @traced decorator for sync and async code, two exporters (InMemoryExporter and JsonlExporter), and Tracer.record() for spans that already finished
  • Privacy by default: only the exception class name is recorded, never its message; only str, int, float and bool attribute values are kept (objects are dropped, never printed); keys such as prompt, answer, query, file_name, password and token are 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
  • JsonlExporter creates files with mode 0600 and refuses an existing file that group or others can read
  • An adapter for ragleap-rag, RagTraceAdapter, turns its on_ingest, on_query and on_answer hooks 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.

PyPI page Source Changelog Release notes Tests