A Python dynamic debugger inspired by Arthas, using Python 3.14's safe external debugger interface
Project description
Peeka
中文 | English
Roadmap: English | 中文
Peek-a-boo! — The name comes from the children's game. A diagnostic tool finding a hidden bug feels just like that moment of surprise when someone is found in hide-and-seek.
Runtime diagnostic tool for Python applications, inspired by Alibaba Arthas. Non-invasive function observation with zero code changes.
Uses PEP 768 (sys.remote_exec) on Python 3.14+, with debugger-based fallback for Python 3.8–3.13 (GDB on Linux, LLDB on macOS).
Key Features
- Non-invasive — Inject observation logic at runtime, fully restored on detach
- Real-time streaming — Millisecond-latency data via Unix domain sockets
- Production-safe — < 5% overhead, fixed-size memory buffers, graceful error recovery
- Secure filtering — simpleeval-based condition expressions, blocks all code injection
- Dual interface — CLI (JSONL output, pipe-friendly) and interactive TUI
Quick Start
Install
pip install peeka # CLI only (Python 3.8+)
pip install peeka[tui] # CLI + TUI (Python 3.9+)
Basic Usage
# 1. Attach to a running Python process
peeka-cli attach <pid>
# 2. Watch function calls
peeka-cli watch "module.Class.method" -n 5
# 3. Watch with condition filter
peeka-cli watch "module.func" --condition "params[0] > 100"
# 4. Trace call tree with timing
peeka-cli trace "module.func" -d 3
# 5. Capture call stack
peeka-cli stack "module.func" -n 3
# 6. Launch TUI
peeka
Pipe-Friendly Output (JSONL)
All CLI output is JSONL — one JSON object per line with a type field:
# Filter observations with jq
peeka-cli watch "module.func" | jq 'select(.type == "observation")'
# Find slow calls
peeka-cli watch "module.func" | jq 'select(.type == "observation" and .data.duration_ms > 100)'
# Save to file
peeka-cli watch "module.func" > observations.jsonl
Commands
| Command | Description |
|---|---|
attach |
Attach to a running Python process |
watch |
Observe function calls (args, return, time) |
trace |
Trace call tree with timing breakdown |
stack |
Capture call stack at function entry |
monitor |
Periodic performance statistics |
logger |
Adjust log levels at runtime |
memory |
Memory usage analysis |
inspect |
Runtime object inspection |
sc/sm |
Search classes / search methods |
thread |
Thread analysis and diagnostics |
top |
Function-level performance sampling |
reset |
Remove all injected enhancements |
detach |
Detach from target process |
run |
Run a script with Peeka injected from startup |
watch
peeka-cli watch <pattern> [options]
| Option | Description | Default |
|---|---|---|
-x, --depth |
Output depth for nested objects | 2 |
-n, --times |
Number of observations (-1 = infinite) | -1 |
--condition |
Filter expression (e.g. params[0] > 100, cost > 50) |
— |
-b, --before |
Observe at function entry | false |
-s, --success |
Observe on success only | false |
-e, --exception |
Observe on exception only | false |
-f, --finish |
Observe on finish (success or exception) | true |
Pattern format: module.Class.method or module.function
trace
peeka-cli trace <pattern> [options]
| Option | Description | Default |
|---|---|---|
-d, --depth |
Max call tree depth | 3 |
-n, --times |
Number of observations (-1 = infinite) | -1 |
--condition |
Filter expression (e.g. cost > 50) |
— |
--skip-builtin |
Skip stdlib/built-in functions | true |
--min-duration |
Minimum duration filter (ms) | 0 |
Output example:
`---[125.3ms] calculator.Calculator.calculate()
+---[2.1ms] calculator.Calculator._validate()
+---[98.2ms] calculator.Calculator._compute()
| `---[95.1ms] math.sqrt()
`---[15.7ms] calculator.Logger.info()
stack
peeka-cli stack <pattern> [options]
| Option | Description | Default |
|---|---|---|
-n, --times |
Number of captures (-1 = infinite) | -1 |
--condition |
Filter expression | — |
--depth |
Stack depth limit | 10 |
reset
peeka-cli reset [pattern] [options]
| Option | Description | Default |
|---|---|---|
-l, --list |
List current enhancements without reset | false |
pattern |
Optional glob pattern to filter targets | — |
peeka-cli reset # Reset all enhancements
peeka-cli reset "mymodule.*" # Reset matching functions only
peeka-cli reset --list # List active enhancements
run
Run a Python script with Peeka injected from startup — useful when you need to observe code that runs at import time or in short-lived scripts.
peeka-cli run <script> [script_args] -- <command> [command_options]
peeka-cli run myscript.py -- watch "mymodule.func"
peeka-cli run myscript.py arg1 arg2 -- trace "mymodule.func" -d 3
peeka-cli run myscript.py -- watch "mymodule.func" --output-file out.jsonl
| Option | Description | Default |
|---|---|---|
--output-file |
Write JSONL output to file instead of stdout | — |
Condition Expressions
Powered by simpleeval for safe evaluation:
params[0] > 100 # Positional argument check
len(params) > 2 # Argument count
kwargs.get('debug') == True # Keyword argument check
cost > 50 # Execution time in ms (watch/trace only)
str(x).startswith('prefix') # String operations
x + y > 10 # Arithmetic
Available variables: params (positional args list), kwargs (keyword args dict), result (return value, finish only), cost (duration ms, watch/trace only).
Security: Only safe operations (comparisons, arithmetic, logic) are allowed. eval, exec, __import__, open, compile and reflection via __class__/__subclasses__ are all blocked.
Output Format
Every line is a JSON object with a type field:
| Type | Description | Commands |
|---|---|---|
status |
Progress/info messages | attach |
success |
Command completed successfully | attach, detach |
error |
Command failed | all |
event |
Control events (started/stopped) | watch, stack, monitor |
observation |
Real-time observation data | watch, stack, monitor |
result |
Query results (non-streaming) | logger, memory, sc, sm |
Output examples
{"type": "status", "level": "info", "message": "Attaching to process 12345"}
{"type": "success", "command": "attach", "data": {"pid": 12345, "socket": "/tmp/peeka_xxx.sock"}}
{"type": "event", "event": "watch_started", "data": {"watch_id": "watch_001", "pattern": "module.func"}}
{
"type": "observation",
"watch_id": "watch_001",
"timestamp": 1705586200.123,
"func_name": "demo.Calculator.add",
"args": [1, 2],
"kwargs": {},
"result": 3,
"success": true,
"duration_ms": 0.123,
"count": 1
}
{"type": "error", "command": "watch", "error": "Cannot find target: invalid.pattern"}
Python Version Support
| Python Version | CLI | TUI | Attach Mechanism | Requirements |
|---|---|---|---|---|
| 3.14+ | ✅ | ✅ | PEP 768 sys.remote_exec() |
Same UID or CAP_SYS_PTRACE |
| 3.9–3.13 | ✅ | ✅ | GDB (Linux) / LLDB (macOS) | Linux: GDB 7.3+, ptrace ≤ 1 macOS: Xcode Command Line Tools |
| 3.8 | ✅ | ❌ | GDB (Linux) / LLDB (macOS) | Linux: GDB 7.3+, ptrace ≤ 1 macOS: Xcode Command Line Tools |
TUI requires Textual which needs Python ≥ 3.9.
Python < 3.14 Setup
Linux
GDB is required. Debug symbols are strongly recommended — some distros include them by default, but if GDB reports "no symbol" errors, install them:
# Debian/Ubuntu
sudo apt-get install gdb python3-dbg
# RHEL/Fedora
sudo yum install gdb python3-debuginfo
# Arch
sudo pacman -S gdb
macOS
LLDB is used instead of GDB. Install Xcode Command Line Tools if not already installed:
xcode-select --install
LLDB is included by default. No additional debug symbols are required.
Docker
docker run --cap-add=SYS_PTRACE your-image
ptrace Restrictions (Linux)
# Check current setting
cat /proc/sys/kernel/yama/ptrace_scope
# Temporarily allow (for testing)
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
# SELinux (Fedora/RHEL)
sudo setsebool -P deny_ptrace=off
Note: macOS does not have ptrace_scope restrictions. System Integrity Protection (SIP) may prevent debugging some system processes, but user processes can be debugged normally.
Troubleshooting
Attach fails (permission denied)
- Ensure same UID or
CAP_SYS_PTRACE - Linux: Check
ptrace_scope(see above) - Linux: Install debug symbols if GDB reports "no symbol" errors
- macOS: Ensure Xcode Command Line Tools are installed (
xcode-select --install)
No observation data
- Verify function name (use fully qualified name:
module.Class.method) - Confirm the function is actually being called
- Check if condition expression is too restrictive
Target process behaving abnormally
# Remove observation on specific function
peeka-cli reset "module.func"
# Remove all injected enhancements
peeka-cli reset
# If issues persist, detach and restart target process
peeka-cli detach <pid>
Architecture
CLI/TUI → AgentClient → Unix Socket → PeekaAgent (injected in target)
├─ _register_handlers() → BaseCommand subclasses
├─ DecoratorInjector (function wrapping)
└─ ObservationManager (buffered streaming)
- Attach: PEP 768
sys.remote_exec()on 3.14+, GDB (Linux) or LLDB (macOS) on 3.8–3.13 - Observe: Decorator injection wraps target functions, captures args/return/exceptions/timing
- Stream: Real-time observation data via Unix domain socket (length-prefixed JSON)
- Commands: Modular
BaseCommandsubclasses, registered inPeekaAgent._register_handlers()
License
Apache License 2.0
Acknowledgments
- Inspired by Alibaba Arthas
- Safe evaluation: simpleeval
- Remote debugging protocol: PEP 768
Project details
Release history Release notifications | RSS feed
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 peeka-0.1.10.tar.gz.
File metadata
- Download URL: peeka-0.1.10.tar.gz
- Upload date:
- Size: 136.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
380a3d8b6c342f78efadb9c084094a4d6b5cc61c4e4174597a0f8f06574b70cf
|
|
| MD5 |
49ef1593fa6592b7738816b50b5cb1f7
|
|
| BLAKE2b-256 |
b7f93dfd806e23820f8d3efbdd73430c61fd27c975bfaf93bb021b1199c5d0d9
|
Provenance
The following attestation bundles were made for peeka-0.1.10.tar.gz:
Publisher:
publish-pypi.yml on wwulfric/peeka
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
peeka-0.1.10.tar.gz -
Subject digest:
380a3d8b6c342f78efadb9c084094a4d6b5cc61c4e4174597a0f8f06574b70cf - Sigstore transparency entry: 1437380312
- Sigstore integration time:
-
Permalink:
wwulfric/peeka@fa57093b465902268d8598b1e911a25aa2ee4e4d -
Branch / Tag:
refs/tags/v0.1.10 - Owner: https://github.com/wwulfric
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@fa57093b465902268d8598b1e911a25aa2ee4e4d -
Trigger Event:
push
-
Statement type:
File details
Details for the file peeka-0.1.10-cp312-cp312-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: peeka-0.1.10-cp312-cp312-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 180.2 kB
- Tags: CPython 3.12, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
517d1e080967fc415b1abb9bb9d39ec4e5436aa58ef6a900b8b0c13713c47d58
|
|
| MD5 |
adf79c51a3266e428b4ed7747b2e2207
|
|
| BLAKE2b-256 |
b8c4a7a20677b350b9444852c7b9d06a571893b235e8c86b0d978ef772807ba0
|
Provenance
The following attestation bundles were made for peeka-0.1.10-cp312-cp312-manylinux_2_34_x86_64.whl:
Publisher:
publish-pypi.yml on wwulfric/peeka
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
peeka-0.1.10-cp312-cp312-manylinux_2_34_x86_64.whl -
Subject digest:
517d1e080967fc415b1abb9bb9d39ec4e5436aa58ef6a900b8b0c13713c47d58 - Sigstore transparency entry: 1437380313
- Sigstore integration time:
-
Permalink:
wwulfric/peeka@fa57093b465902268d8598b1e911a25aa2ee4e4d -
Branch / Tag:
refs/tags/v0.1.10 - Owner: https://github.com/wwulfric
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@fa57093b465902268d8598b1e911a25aa2ee4e4d -
Trigger Event:
push
-
Statement type: