Skip to main content

A lightweight Python code profiler and log reporter. Inspect execution time, memory, call stacks, and bottlenecks with minimal overhead.

Project description

sondeoSocialClose

Sondeo

Lightweight Python Code Profiler

Zero dependencies. Stdlib only. One decorator away.

PyPI Downloads Python License Stars

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

sondeo-0.0.3.tar.gz (31.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sondeo-0.0.3-py3-none-any.whl (28.0 kB view details)

Uploaded Python 3

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

Hashes for sondeo-0.0.3.tar.gz
Algorithm Hash digest
SHA256 2e28c02633332b8c75b3c7f2308dec979ae62775f0d06694f3757b9e51b05361
MD5 84f11abcab08d91bb8bfdda150cff23a
BLAKE2b-256 36694a80e1720888d9f615e59dd184ebe6a95b36d1327da94cbb9884408bd1d9

See more details on using hashes here.

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

Hashes for sondeo-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e444db30b9d7f7f9bdacbad27b5d39e63a3259757f780dd736e2edcd97e1c51c
MD5 7be046bd6cd537dcba429b778066c95e
BLAKE2b-256 91aa883a112e6213c0a12521d8db31ece15d779cd71227dfb618fbca0d2446c5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page