Scope-aware SQL query tracing for Python applications, tests, and offline reports.
Project description
QueryArgus
See every query. Miss nothing.
QueryArgus is a Python library for tracing SQL queries across requests, jobs, tests, CLI commands, and regular functions. It captures query execution with business context, stores finished traces in simple offline-friendly formats, and helps you understand repeated queries, hotspots, and possible N+1 sequences without forcing an APM-shaped workflow on your application.
Portuguese (Brazil) documentation
Why QueryArgus
Database behavior often becomes opaque as an application grows:
- N+1 issues slip into production unnoticed.
- Performance regressions show up late.
- Generic APMs reveal symptoms, but not the actual query flow inside the unit of work you care about.
- Plain logs rarely connect a query to the request, job, or repository method that caused it.
QueryArgus exists to make query behavior visible, understandable, and actionable.
What it does
- Captures SQL queries through pluggable adapters.
- Associates queries with a root trace and nested business scopes.
- Infers a useful scope from caller code when you do not set one explicitly.
- Works in HTTP apps, background jobs, worker handlers, tests, and CLI code.
- Persists finished traces to JSONL or memory sinks.
- Generates offline reports in text, JSON, HTML, SVG badge, and Markdown summary formats.
- Provides pytest fixtures and assertions for query-aware tests.
Installation
Install the core package:
pip install queryargus
Install common integrations:
pip install "queryargus[sqlalchemy,fastapi,testing]"
Available extras:
sqlalchemy: SQLAlchemyEngineandAsyncEngineinstrumentation.psycopg: psycopg 3 sync and async connection instrumentation.asyncpg: asyncpg connection instrumentation.fastapi: FastAPI and Starlette middleware integration.testing: pytest plugin and testing helpers.
Quick start
setup() is the recommended entrypoint when you want one line to configure sinks, database instrumentation, and framework integration:
from fastapi import FastAPI
from sqlalchemy import create_engine
import queryargus
app = FastAPI()
engine = create_engine("sqlite:///app.db")
queryargus.setup(
adapter=engine,
framework=app,
sink="jsonl",
)
With that in place:
- the SQLAlchemy adapter captures queries automatically
- the FastAPI middleware opens one trace per request
- traces are appended to
traces/queryargus.jsonl
Core usage patterns
FastAPI or Starlette request tracing
from fastapi import FastAPI
from sqlalchemy import create_engine
import queryargus
app = FastAPI()
engine = create_engine("sqlite:///inventory.db")
queryargus.setup(adapter=engine, framework=app, sink="jsonl")
Each HTTP request becomes a root trace named like GET /products.
Jobs, workers, and CLI functions
Use @traced when the function itself is the unit of work:
import queryargus
queryargus.setup(adapter=engine, sink="jsonl")
@queryargus.traced("billing.process_invoice")
def process_invoice(invoice_id: str) -> None:
repository.load_invoice(invoice_id)
service.apply_rules(invoice_id)
repository.mark_processed(invoice_id)
If a trace is already active, @traced does not open a nested root trace.
Manual tracing
Use start_trace() when a context manager fits better than a decorator:
from queryargus import start_trace, trace_scope
with start_trace("inventory.rebuild_projection"):
with trace_scope("inventory_repository.load_snapshot"):
repository.load_snapshot()
Important behavior:
start_trace()raisesNestedTraceErrorif a root trace is already active.trace_scope()is a no-op when there is no active trace.
Automatic business scopes on repositories and services
Instrument a class:
from queryargus import trace_methods
@trace_methods()
class StockRepository:
def get_by_id(self, stock_id: str):
...
def list_all(self):
...
Instrument an existing instance:
from queryargus import instrument_object_methods
repository = instrument_object_methods(repository, namespace="products")
That gives you scope labels such as StockRepository.get_by_id or products.list_all in reports.
Supported adapters and integrations
SQLAlchemy
Auto-detected by setup(adapter=engine) or explicitly installed:
from queryargus.adapters import instrument_sqlalchemy
instrument_sqlalchemy(engine)
psycopg 3
from queryargus.adapters import instrument_psycopg
conn = instrument_psycopg(conn)
asyncpg
from queryargus.adapters import instrument_asyncpg
conn = instrument_asyncpg(conn)
FastAPI and Starlette
Auto-detected by setup(framework=app) or explicitly installed:
from queryargus.integrations.fastapi import instrument_fastapi
from queryargus.integrations.starlette import instrument_starlette
instrument_fastapi(app)
instrument_starlette(app)
Sinks
QueryArgus ships with two built-in sinks:
JsonlSink: appends one serialized trace per line to a JSONL fileMemorySink: keeps traces in memory for tests and local experiments
Examples:
import queryargus
queryargus.setup(sink="jsonl")
queryargus.setup(sink="memory")
queryargus.setup(sink=[queryargus.MemorySink(), queryargus.JsonlSink("var/traces.jsonl")])
When you omit sink, QueryArgus defaults to JsonlSink("traces/queryargus.jsonl").
Testing support
Install the testing extra:
pip install "queryargus[testing]"
Pytest fixtures exposed through the pytest11 entry point:
queryargus_memory_sinkqueryargus_tracequeryargus_captured
Useful helpers:
from queryargus.testing import (
assert_all_queries_scoped,
assert_max_duration_ms,
assert_no_n_plus_one,
assert_no_repeated_queries,
assert_query_count_at_most,
capture_queries,
)
Example:
def test_repository_is_efficient(queryargus_trace):
repository.list_products()
assert_query_count_at_most(queryargus_trace, 3)
assert_no_n_plus_one(queryargus_trace)
Offline reports
Generate an offline report from collected traces:
queryargus-report PATH [--format text|json|html|badge|summary] [--output OUTPUT]
Examples:
queryargus-report traces/queryargus.jsonl --format html
queryargus-report traces/queryargus.jsonl --format summary --output artifacts/queryargus-summary.md
queryargus-report traces/queryargus.jsonl --format badge --output artifacts/queryargus-coverage.svg
queryargus-report traces/queryargus.jsonl --format badge --badge-type n-plus-one --output artifacts/queryargus-n-plus-one.svg
Analytic Visions (--format):
html: Analytic View: Full interactive report for deep navigation, hotspot analysis, and N+1. (Recommended for local use)summary: Code Review View: Markdown summary ideal for Pull Request comments or CI logs.badge: Status View: Visual badge for displaying coverage percentage in READMEs. Use--badge-type n-plus-oneto generate an N+1 badge.text: Terminal View: Quick summary for immediate check in the console.json: Data View: Full structured payload for integrations and automation.
Output behavior:
<input_stem>_queryargus_report- For
html,--outputis a directory. - For
summaryandbadge,--outputis a file path.
The HTML report includes coverage summaries, entrypoint breakdowns, hotspot analysis, and N+1 detection.
Project files
- English guide:
README.md - Brazilian Portuguese guide:
README.pt-BR.md - Contribution guide:
CONTRIBUTING.md - Change history:
CHANGELOG.md
Compatibility
- Python
>=3.10,<3.15 - Typed package (
py.typedincluded) - Offline-first JSONL workflow by default
- Designed for application code, tests, and CI pipelines
Development status
The package is ready for early professional usage and packaging, with a deliberately small public API. The current release focuses on reliable trace capture, scope-aware analysis, and offline reporting.
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 queryargus-0.1.1.tar.gz.
File metadata
- Download URL: queryargus-0.1.1.tar.gz
- Upload date:
- Size: 37.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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 |
a8be91c3349f60a01ae0868c2d3ba65980998ef1ea6338624a97677165364f03
|
|
| MD5 |
79a55ad7015b7823b2dd2f6b1e34da2a
|
|
| BLAKE2b-256 |
8eb09f6224554893c8b08ce2dff60b42f0b74c9d9aeb7c47a759f6c367c583f3
|
File details
Details for the file queryargus-0.1.1-py3-none-any.whl.
File metadata
- Download URL: queryargus-0.1.1-py3-none-any.whl
- Upload date:
- Size: 53.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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 |
6a1f7dec5bfa82898fab53060168226efa8a6935219eb4f5355825d4a7586807
|
|
| MD5 |
99c0fe3b378dc50138e7e12d5441ea7a
|
|
| BLAKE2b-256 |
845ecfd965ecadd04913a8fd9a37c10046ab9ed2a7a27f9026a8d4e116bf69d0
|