Function-level CPU and Memory monitoring with visual terminal output
Project description
๐ taskmon - Function-Level Performance Monitoring
Simple, powerful Python function monitoring with beautiful terminal output.
Track CPU, memory, and performance of any Python function with a simple decorator. Perfect for finding memory leaks, bottlenecks, and understanding your code's resource usage.
โจ Features
- ๐ฏ Function-level tracking - Monitor any function with a simple
@monitor()decorator - ๐ Real-time metrics - CPU, memory, execution time, and throughput
- ๐จ Beautiful output - Color-coded, visual terminal display
- ๐ Memory leak detection - Automatic detection of memory growth
- ๐ Nested function support - Track call hierarchies with visual indentation
- ๐ Zero configuration - Works out of the box
- ๐ Aggregated statistics - See summaries across all function calls
- ๐งต Thread-safe - Works with multi-threaded applications
๐ Quick Start
Installation
pip install taskmon
Or install from source:
git clone https://github.com/kadirtutenn/taskmon
cd taskmon
pip install -e .
Basic Usage
from taskmon import monitor
@monitor()
def process_data(items):
result = []
for item in items:
result.append(item * 2)
return result
# Call your function normally
data = process_data([1, 2, 3, 4, 5])
Output:
โโ ๐ process_data() started [call_1_1738574400123]
โ ๐ Baseline: CPU 2.3% | MEM 156.2MB | THR 4
โโ โ
process_data() completed in 0.02s
๐ CPU: 3.1% [โโโโโโโโโโ] | MEM: ๐ข +0.8MB (peak: 157.0MB)
โก Processed: 5 items (250.0 items/s)
๐ Usage Examples
1. Monitor Any Function
from taskmon import monitor
@monitor()
def calculate_fibonacci(n):
if n <= 1:
return n
return calculate_fibonacci(n-1) + calculate_fibonacci(n-2)
result = calculate_fibonacci(10)
2. Track Code Sections
from taskmon import monitor, track
@monitor()
def data_pipeline():
with track("load_data"):
data = load_from_database()
with track("process"):
processed = process_data(data)
with track("save"):
save_to_database(processed)
data_pipeline()
Output shows nested structure:
โโ ๐ data_pipeline() started
โ ๐ Baseline: CPU 2.1% | MEM 145.3MB | THR 4
โโ ๐ load_data started
โ ๐ Baseline: CPU 2.3% | MEM 145.5MB | THR 4
โโ โ
load_data completed in 1.23s
๐ CPU: 15.2% [โโโโโโโโโโ] | MEM: ๐ข +12.3MB (peak: 157.8MB)
โโ ๐ process started
โ ๐ Baseline: CPU 3.1% | MEM 157.8MB | THR 4
โโ โ
process completed in 2.45s
๐ CPU: 45.6% [โโโโโโโโโโ] | MEM: ๐ก +45.2MB (peak: 203.0MB)
โโ โ
data_pipeline() completed in 3.89s
๐ CPU: 21.3% [โโโโโโโโโโ] | MEM: ๐ข +9.1MB (peak: 203.0MB)
3. Track Items Processed
from taskmon import monitor
@monitor()
def process_batch(items):
results = []
for item in items:
results.append(transform_item(item))
return results
# Automatically tracks len(results)
items = ["item1", "item2", "item3"]
process_batch(items)
Output:
โโ โ
process_batch() completed in 5.23s
๐ CPU: 12.3% [โโโโโโโโโโ] | MEM: ๐ข +2.1MB (peak: 158.4MB)
โก Processed: 3 items (0.6 items/s)
4. View Statistics
from taskmon import monitor, print_summary
@monitor()
def expensive_function(n):
time.sleep(n)
return n * 2
# Call multiple times
for i in range(5):
expensive_function(i)
# Print summary
print_summary()
Output:
================================================================================
๐ FUNCTION MONITORING SUMMARY
================================================================================
Function Calls Total Time Avg Time Failures
--------------------------------------------------------------------------------
__main__.expensive_function 5 10.00s 2.000s 0 (0.0%)
================================================================================
5. Find Memory Leaks
from taskmon import monitor
@monitor()
def potential_leak():
data = []
for i in range(1000000):
data.append(i)
# Oops, forgot to clean up!
return len(data)
potential_leak()
Output (notice the ๐ด red indicator):
โโ โ
potential_leak() completed in 0.15s
๐ CPU: 85.2% [โโโโโโโโโโ] | MEM: ๐ด +156.3MB (peak: 312.5MB)
โก Processed: 1,000,000 items (6666666.7 items/s)
6. Real-World Example: Space Mission Data Pipeline
from taskmon import monitor, track
@monitor()
def plan_mission_data_collection():
with track("Load Configuration"):
satellites = get_satellite_config_cached()
with track("Count Signals"):
total_signals = get_total_signal_count()
# Process in chunks
chunk_size = 50000
for offset in range(0, total_signals, chunk_size):
with track(f"Process Chunk {offset//chunk_size + 1}"):
process_signal_chunk(offset, chunk_size, satellites)
plan_mission_data_collection()
Output shows where memory leaks occur:
โโ ๐ plan_mission_data_collection() started
โโ ๐ Load Configuration started
โโ โ
Load Configuration completed in 0.05s
๐ CPU: 2.1% | MEM: ๐ข +1.2MB
โโ ๐ Count Signals started
โโ โ
Count Signals completed in 0.23s
๐ CPU: 5.3% | MEM: ๐ข +0.1MB
โโ ๐ Process Chunk 1 started
โโ โ
Process Chunk 1 completed in 12.34s
๐ CPU: 45.2% | MEM: ๐ข +2.3MB
โโ ๐ Process Chunk 2 started
โโ โ
Process Chunk 2 completed in 11.89s
๐ CPU: 43.1% | MEM: ๐ด +125.6MB <-- Memory leak here!
โโ โ
plan_mission_data_collection() completed in 45.67s
๐ CPU: 38.5% | MEM: ๐ด +128.4MB
๐จ Visual Indicators
Status Icons
- ๐ Function started
- โ Successfully completed
- โ Failed with error
- โ ๏ธ Warning
Memory Status
- ๐ข Green: < 10MB change (normal)
- ๐ก Yellow: 10-100MB change (monitor)
- ๐ด Red: > 100MB change (memory leak!)
CPU Bars
CPU: 15.2% [โโโโโโโโโโ] <- Visual bar
CPU: 45.6% [โโโโโโโโโโ]
CPU: 85.2% [โโโโโโโโโโ]
๐ API Reference
@monitor(items_attr=None, print_summary=False, logger=None, use_color=None)
Decorator to monitor function performance.
Parameters:
items_attr(str, optional): Attribute name to track as items_processedprint_summary(bool): Print summary after function completeslogger(optional): Logger instance or callable (e.g.logging.Logger, Celery logger)use_color(bool, optional): Enable/disable ANSI colors for this function
Example:
@monitor(items_attr='count', print_summary=True)
def process_data():
return {"count": 100, "data": [...]}
@monitor(logger=my_logger, use_color=False)
def task():
pass
track(section_name, items=0, logger=None, use_color=None)
Context manager for monitoring code sections.
Parameters:
section_name(str): Name of the sectionitems(int): Number of items processedlogger(optional): Logger instance or callableuse_color(bool, optional): Enable/disable ANSI colors for this section
Example:
with track("database_query", items=100):
results = db.query(...)
with track("cache_warmup", logger=my_logger, use_color=False):
warmup()
get_stats(function_name=None)
Get function statistics.
Parameters:
function_name(str, optional): Specific function name, or None for all
Returns: Dict with statistics
Example:
stats = get_stats("my_module.my_function")
print(f"Total calls: {stats['total_calls']}")
print(f"Avg CPU: {stats['avg_cpu']:.1f}%")
print_summary(logger=None)
Print summary of all monitored functions.
set_logger(logger, use_color=None)
Set default logger and color behavior for all outputs.
clear_stats()
Clear all statistics.
get_active_calls()
Get list of currently active function calls.
Returns: List of FunctionMetrics objects
๐ง Advanced Usage
Custom Items Tracking
@monitor()
def process_batch(items):
count = 0
for item in items:
process(item)
count += 1
return count # Automatically tracked
Nested Function Monitoring
@monitor()
def parent_function():
child_function_1()
child_function_2()
@monitor()
def child_function_1():
pass
@monitor()
def child_function_2():
pass
Output shows hierarchy:
โโ ๐ parent_function() started
โโ ๐ child_function_1() started
โโ โ
child_function_1() completed
โโ ๐ child_function_2() started
โโ โ
child_function_2() completed
โโ โ
parent_function() completed
Integration with Celery
from celery import shared_task
from celery.utils.log import get_task_logger
from taskmon import monitor
celery_logger = get_task_logger(__name__)
@shared_task
@monitor(logger=celery_logger, use_color=False)
def celery_task(data):
process(data)
Logger Integration
import logging
from taskmon import set_logger, monitor, track
logger = logging.getLogger("myapp.taskmon")
set_logger(logger, use_color=False)
@monitor()
def pipeline():
with track("step_1"):
pass
Programmatic Access
from taskmon import get_active_calls, get_stats
# Get currently running functions
active = get_active_calls()
for call in active:
print(f"{call.function_name}: {call.memory_delta_mb:.1f}MB")
# Get historical stats
stats = get_stats()
for func_name, metrics in stats.items():
if metrics['avg_cpu'] > 50:
print(f"High CPU function: {func_name}")
๐ฏ Use Cases
1. Find Memory Leaks
@monitor()
def suspect_function():
# Your code
pass
Look for ๐ด indicators showing large memory growth.
2. Identify Bottlenecks
@monitor()
def pipeline():
with track("step1"):
slow_step()
with track("step2"):
fast_step()
See which sections take the most time.
3. Optimize Batch Processing
@monitor()
def process_chunks():
for chunk in chunks:
with track(f"chunk_{i}"):
process(chunk)
Identify which chunks are slow or leak memory.
4. Monitor Production Code
@monitor()
def critical_api_endpoint():
# Monitor in production
pass
Track performance metrics over time.
๐ Performance Overhead
taskmon is designed to be lightweight:
- CPU overhead: < 1% in most cases
- Memory overhead: < 1MB
- Sampling: Background thread samples every 1 second
- Thread-safe: Safe for multi-threaded applications
๐ Troubleshooting
Output not showing colors?
Set your terminal to support ANSI colors:
export TERM=xterm-256color
Or disable colors:
from taskmon import set_logger
set_logger(my_logger, use_color=False)
Too much output?
Disable monitoring for specific functions:
# Just remove the decorator
def my_function():
pass
Want quieter output?
The library respects standard output - redirect if needed:
import sys
sys.stdout = open('monitor.log', 'w')
๐ค Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Submit a pull request
๐ License
MIT License - see LICENSE file for details.
๐ Acknowledgments
Built with:
- psutil - Process and system utilities
๐ Support
- ๐ง Email: kadirsmdb@gmail.com
- ๐ Issues: GitHub Issues
- ๐ฌ Discussions: GitHub Discussions
Made with โค๏ธ for Python developers who care about performance
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 taskmon-0.1.1.tar.gz.
File metadata
- Download URL: taskmon-0.1.1.tar.gz
- Upload date:
- Size: 40.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f0f7e292489ee8cf9fb4538237b11f63b813bf57a49be1ab2c6b41e4ab815fd
|
|
| MD5 |
79fcbebf248c2ef6ce6662a959514e55
|
|
| BLAKE2b-256 |
d74d6aea50464498216d5706720bbf2827e31d26dd9fe72302d97bc9ef779127
|
File details
Details for the file taskmon-0.1.1-py3-none-any.whl.
File metadata
- Download URL: taskmon-0.1.1-py3-none-any.whl
- Upload date:
- Size: 22.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d5e4c6367773a6eff98fd970c58f3174e4221c538542dd8a16e2dcc2b447c8e
|
|
| MD5 |
887d696b14fd3f3102e2aafa2a086538
|
|
| BLAKE2b-256 |
1f571d48275dc035b8241c5b4b6b775dd514940f2abece10fd3be12bf2c4e8e2
|