Sondeo
Lightweight Python code profiler and log reporter. Inspect execution time, memory, call stacks, and bottlenecks — zero dependencies, stdlib only, one decorator away.
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():
...
# 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")
# 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.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}")
# 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 --format json
# Sort by total time, show top 30 entries
sondeo run app.py --sort tottime --top 30
# Check version
sondeo --version
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>
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
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
Part of the Cacao Ecosystem
Sondeo is a standalone tool under cacao-research. Install sondeo[ui] for an interactive Cacao-powered dashboard, or look forward to a future cacao-sondeo plugin for live profiling panels embedded directly in your Cacao apps.
License
MIT
Metadata
Release files for sondeo 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sondeo-0.1.0.tar.gz | 27.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sondeo-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 54.9 kB
Release files / sondeo-0.1.0.tar.gz
| Download URL | sondeo-0.1.0.tar.gz |
|---|---|
| Size | 27.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f223265782bd46fbb20f43d16bcb3fc0b53779d806cab4ecbcad48e58840840e
|
|
BLAKE2b-256 checksum How to use checksums |
f2f461bb3043f7a2b5f45695e56a352e75d87f45a6019b68539a9d573a7ea677
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.7
|
Release files / sondeo-0.1.0-py3-none-any.whl
| Download URL | sondeo-0.1.0-py3-none-any.whl |
|---|---|
| Size | 27.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f577c31f05879e4827c37d0d09a8159cecd9792b9d181aa8cde510b8a4088dc8
|
|
BLAKE2b-256 checksum How to use checksums |
fd9290157af1dcc87810cd9ab782383116df7dc7f3f3b9357bd18125be69a91b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.7
|