A lightweight Python code profiler and log reporter. Inspect execution time, memory, call stacks, and bottlenecks with minimal overhead.
Project description
Sondeo
Lightweight Python Code Profiler
Zero dependencies. Stdlib only. One decorator away.
Inspect execution time, memory, call stacks, and bottlenecks — probe your code, survey its performance, report what it finds.
Quick Start · Why Sondeo · Core API · CLI · Architecture
Sondeo (Spanish: "probe", "survey") — probe your code, survey its performance, report what it finds.
Quick Start
pip install sondeo
Profile a function (2 lines)
from sondeo import profile, report
@profile
def process_data():
return sum(range(1_000_000))
process_data()
report()
============================================================
SONDEO PROFILING REPORT
============================================================
TIMING
--------------------------------------------------------
process_data 12.34ms (4 calls)
============================================================
Track memory allocations
from sondeo import memprof, report
@memprof
def allocate_heavy():
matrix = [[0] * 1000 for _ in range(1000)]
return matrix
allocate_heavy()
report()
============================================================
SONDEO PROFILING REPORT
============================================================
MEMORY
--------------------------------------------------------
allocate_heavy peak=38.21MB alloc=7.63MB
============================================================
Trace call trees
from sondeo import trace
with trace() as t:
result = build_pipeline()
t.print_tree()
build_pipeline (45.12ms) [pipeline.py:23]
load_config (2.31ms) [config.py:8]
connect_db (18.44ms) [db.py:15]
authenticate (5.22ms) [auth.py:31]
pool_connection (12.91ms) [db.py:42]
run_query (24.01ms) [db.py:67]
Time any block
from sondeo import timer
with timer("data loading"):
data = load_csv("users.csv")
with timer("processing"):
result = transform(data)
with timer("export"):
save_parquet(result, "output.parquet")
Why Sondeo?
| Feature | Sondeo | cProfile | py-spy | scalene |
|---|---|---|---|---|
| Setup | @profile — done |
Manual Profile() + pstats |
External process | Separate command |
| Dependencies | Zero (stdlib only) | stdlib | Rust binary | C extensions |
| Memory profiling | Built-in @memprof |
No | No | Yes |
| Call trees | Built-in trace() |
Manual parsing | Flamegraph only | No |
| Overhead | Minimal — opt-in per function | All-or-nothing | Sampling | Sampling |
| Output | Text, JSON, HTML | pstats files | SVG | HTML |
| Composable | Decorators + context managers | One mode | One mode | One mode |
Core API
Decorators
from sondeo import profile, memprof
# Time profiling with cProfile under the hood
@profile
def fast_function():
...
# With options
@profile(sort_by="tottime", top_n=10, print_stats=True)
def detailed_function():
...
# Async functions are supported too
@profile
async def fetch_all():
...
# Memory profiling with tracemalloc
@memprof
def memory_heavy():
...
# With options
@memprof(top_n=5, trace_depth=5)
def deep_memory():
...
Structured Logging
from sondeo import log, profile, report
@log(level="debug")
@profile
def process_user(user_id: int) -> dict[str, int]:
log("loading user", user_id, level="info")
return {"id": user_id}
process_user(42)
# Timeline includes both profiling + log events
report()
# Filter timeline to specific modules/levels/patterns
report(format="json", include_modules=["myapp"], levels=["warn", "error"], pattern="db")
Context Managers
from sondeo import timer, trace
# Time a block
with timer("my operation") as t:
do_work()
print(f"Took {t.elapsed_ms:.2f}ms")
# Async timing
async with timer("async operation") as t:
await do_async_work()
print(f"Took {t.elapsed_ms:.2f}ms")
# Trace all calls in a block
with trace(filter_stdlib=True) as t:
complex_operation()
t.print_tree(min_ms=0.5) # Only show calls > 0.5ms
Reporting
from sondeo import report
# Print human-readable report
report()
# Get structured JSON
data = report(format="json")
# Report without clearing collected data
report(clear=False)
Programmatic Access
from sondeo.profiler.timer import get_results, clear_results
from sondeo.profiler.timer import get_async_task_stats, get_concurrency_hints
from sondeo.profiler.memory import get_results as get_memory_results
# Access raw results
for result in get_results():
print(f"{result.name}: {result.elapsed_ms}ms ({result.calls} calls)")
for mem in get_memory_results():
print(f"{mem.name}: peak={mem.peak_mb}MB")
for alloc_line, size_mb in mem.top_allocations:
print(f" {alloc_line}")
# Async task slow-path tracking
for task in get_async_task_stats():
print(task.task_name, task.slowest_ms)
# Heuristic deadlock/contention hints
for hint in get_concurrency_hints():
print("hint:", hint)
# Clear when done
clear_results()
Call Tree Serialization
from sondeo import trace
with trace() as t:
my_pipeline()
# Export as dict (for JSON, databases, dashboards)
tree_data = t.to_dict()
# {
# "total_calls": 42,
# "children": [
# {"name": "my_pipeline", "elapsed_ms": 123.4, "self_ms": 5.2,
# "children": [...]},
# ]
# }
CLI
# Profile an entire script
sondeo run app.py
# JSON output for piping
sondeo run app.py --report json
# Open Cacao dashboard
sondeo run app.py --report ui
# Sort by total time, show top 30 entries
sondeo run app.py --sort tottime --top 30
# Render a saved JSON report as markdown (CI-friendly)
sondeo report .sondeo/latest.json --format markdown
# Check version
sondeo --version
Optional Extras
pip install sondeo[rich] # Colored tables, tree views, sparklines
pip install sondeo[html] # Self-contained HTML reports with flamegraphs
pip install sondeo[ui] # Interactive Cacao dashboard
pip install sondeo[all] # Everything
Architecture
┌──────────────────────────────────────────────────────────┐
│ YOUR CODE │
│ │
│ @profile @memprof with trace() │
│ │ │ │ │
└──────┼─────────────────┼───────────────────┼─────────────┘
│ │ │
┌──────┴─────────────────┴───────────────────┴─────────────┐
│ SONDEO CORE │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌────────────────┐ │
│ │ timer │ │ memory │ │ trace │ │
│ │ cProfile │ │ tracemalloc │ │ sys.settrace │ │
│ │ perf_ctr │ │ snapshots │ │ call trees │ │
│ └────┬─────┘ └──────┬───────┘ └───────┬────────┘ │
│ │ │ │ │
│ └───────────────┼──────────────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ Result Store │ │
│ │ TimingResult │ │
│ │ MemoryResult │ │
│ │ TraceResult │ │
│ └────────┬────────┘ │
│ │ │
└───────────────────────┼──────────────────────────────────┘
│
┌─────────────┼─────────────┐
│ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌────┴─────┐
│ Console │ │ JSON │ │ HTML │
│ report() │ │ export │ │ (planned)│
└───────────┘ └───────────┘ └──────────┘
Project Structure
sondeo/
├── __init__.py # Public API: profile, timer, memprof, trace, report
├── profiler/
│ ├── timer.py # @profile + timer() — cProfile & perf_counter
│ ├── memory.py # @memprof — tracemalloc snapshots & diffs
│ └── trace.py # trace() — sys.settrace call tree capture
├── reporter/
│ └── console.py # Text & JSON output
└── cli/
└── __init__.py # sondeo run <script>
Roadmap
See ROADMAP.md for the full vision. Highlights:
- v0.2 — Structured logging with correlation IDs and timeline view
- v0.3 — Rich reports + Cacao UI dashboard (terminal, browser, CI)
- v0.4 — Async/threading support
- v0.5 — Comparative profiling and regression detection
- v0.6 — Live monitoring with
sondeo attach <pid> - v1.0 — Stable release with documented performance guarantees
Cacao UI
Sondeo is a standalone profiler — not part of the Cacao framework. However, install sondeo[ui] to get an interactive dashboard powered by Cacao for exploring profiling results in your browser.
License
MIT License — see LICENSE for details.
Made with care by Juan Denis
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 sondeo-0.0.3.tar.gz.
File metadata
- Download URL: sondeo-0.0.3.tar.gz
- Upload date:
- Size: 31.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e28c02633332b8c75b3c7f2308dec979ae62775f0d06694f3757b9e51b05361
|
|
| MD5 |
84f11abcab08d91bb8bfdda150cff23a
|
|
| BLAKE2b-256 |
36694a80e1720888d9f615e59dd184ebe6a95b36d1327da94cbb9884408bd1d9
|
File details
Details for the file sondeo-0.0.3-py3-none-any.whl.
File metadata
- Download URL: sondeo-0.0.3-py3-none-any.whl
- Upload date:
- Size: 28.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e444db30b9d7f7f9bdacbad27b5d39e63a3259757f780dd736e2edcd97e1c51c
|
|
| MD5 |
7be046bd6cd537dcba429b778066c95e
|
|
| BLAKE2b-256 |
91aa883a112e6213c0a12521d8db31ece15d779cd71227dfb618fbca0d2446c5
|