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

# 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

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

Uploaded Python 3

File details

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

File metadata

  • Download URL: sondeo-0.1.0.tar.gz
  • Upload date:
  • Size: 27.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for sondeo-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f223265782bd46fbb20f43d16bcb3fc0b53779d806cab4ecbcad48e58840840e
MD5 4980c57b147010261bb22ad65d88edf8
BLAKE2b-256 f2f461bb3043f7a2b5f45695e56a352e75d87f45a6019b68539a9d573a7ea677

See more details on using hashes here.

File details

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

File metadata

  • Download URL: sondeo-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 27.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for sondeo-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f577c31f05879e4827c37d0d09a8159cecd9792b9d181aa8cde510b8a4088dc8
MD5 bc46811e64e42bccb4f0ce3cf4f2cb31
BLAKE2b-256 fd9290157af1dcc87810cd9ab782383116df7dc7f3f3b9357bd18125be69a91b

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