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

Sondeo

PyPI Version Python Versions License GitHub Stars


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():
    ...

# 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

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

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.1.tar.gz (31.5 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.1-py3-none-any.whl (27.7 kB view details)

Uploaded Python 3

File details

Details for the file sondeo-0.0.1.tar.gz.

File metadata

  • Download URL: sondeo-0.0.1.tar.gz
  • Upload date:
  • Size: 31.5 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.1.tar.gz
Algorithm Hash digest
SHA256 e9b87c7f3d1f927e2a7491ff180d00470b6fc57e287d0a3988cfbb898f5ca04a
MD5 6bd73e450ba10c8e4b2da7bbf9b03d51
BLAKE2b-256 969a54d61f745f3119bb29fc372232fa3d5976a77d54de998765a86868903ded

See more details on using hashes here.

File details

Details for the file sondeo-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: sondeo-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 27.7 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 84b8c26ef54d62b2fe3bed1d873f99b12c4bbcbd571be5860ce1899c8b0e8f3d
MD5 75f2990b4c43b0565ffade87c785bdfa
BLAKE2b-256 ff089573d56af83587489ba0ce7bf83bfd11116e8cc6aac4211e32943035c39d

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