Skip to main content

A streaming process monitoring tool

Project description

denet: a streaming process monitor

denet /de.net/ v. 1. Turkish: to monitor, to supervise, to audit. 2. to track metrics of a running process.

Denet is a streaming process monitoring tool that provides detailed metrics on running processes, including CPU, memory, I/O, and thread usage. Built with Rust, with Python bindings.

PyPI version Crates.io codecov Ruff License: GPL v3

Features

  • Lightweight, cross-platform process monitoring
  • Adaptive sampling intervals that automatically adjust based on runtime
  • Memory usage tracking (RSS, VMS)
  • CPU usage monitoring with accurate multi-core support
  • I/O bytes read/written tracking
  • Thread count monitoring
  • Recursive child process tracking
  • Command-line interface with colorized output
  • Multiple output formats (JSON, JSONL, CSV)
  • In-memory sample collection for Python API
  • Python decorator and context manager for easy profiling
  • Analysis utilities for metrics aggregation, peak detection, and resource utilization
  • Process metadata preserved in output files (pid, command, executable path)

Requirements

  • Python 3.6+ (Python 3.12 recommended for best performance)
  • Rust (for development)
  • pixi (for development only)

Installation

pip install denet    # Python package
cargo install denet  # Rust binary

Usage

Understanding CPU Utilization

CPU usage is reported in a top-compatible format where 100% represents one fully utilized CPU core:

  • 100% = one core fully utilized
  • 400% = four cores fully utilized
  • Child processes are tracked separately and aggregated for total resource usage

This is consistent with standard tools like top and htop. For example, a process using 3 CPU cores at full capacity will show 300% CPU usage, regardless of how many cores your system has.

Command-Line Interface

# Basic monitoring with colored output
denet run sleep 5

# Output as JSON (actually JSONL format with metadata on first line)
denet --json run sleep 5 > metrics.json

# Write output to a file
denet --out metrics.log run sleep 5

# Custom sampling interval (in milliseconds)
denet --interval 500 run sleep 5

# Specify max sampling interval for adaptive mode
denet --max-interval 2000 run sleep 5

# Monitor existing process by PID
denet attach 1234

# Monitor just for 10 seconds
denet --duration 10 attach 1234

# Quiet mode (suppress process output)
denet --quiet --json --out metrics.jsonl run python script.py

# Monitor a CPU-intensive workload (shows aggregated metrics for all children)
denet run python cpu_intensive_script.py

Python API

Basic Usage

import json
import denet

# Create a monitor for a process
monitor = denet.ProcessMonitor(
    cmd=["python", "-c", "import time; time.sleep(10)"],
    base_interval_ms=100,    # Start sampling every 100ms
    max_interval_ms=1000,    # Sample at most every 1000ms
    store_in_memory=True,    # Keep samples in memory
    output_file=None         # Optional file output
)

# Let the monitor run automatically until the process completes
# Samples are collected at the specified sampling rate in the background
monitor.run()

# Access all collected samples after process completion
samples = monitor.get_samples()
print(f"Collected {len(samples)} samples")

# Get summary statistics
summary_json = monitor.get_summary()
summary = json.loads(summary_json)
print(f"Average CPU usage: {summary['avg_cpu_usage']}%")
print(f"Peak memory: {summary['peak_mem_rss_kb']/1024:.2f} MB")
print(f"Total time: {summary['total_time_secs']:.2f} seconds")
print(f"Sample count: {summary['sample_count']}")

# Save samples to different formats
monitor.save_samples("metrics.jsonl")          # Default JSONL
monitor.save_samples("metrics.json", "json")   # JSON array format
monitor.save_samples("metrics.csv", "csv")     # CSV format

# JSONL files include a metadata line at the beginning with process info
# {"pid": 1234, "cmd": ["python"], "executable": "/usr/bin/python", "t0_ms": 1625184000000}

# Alternative approach: For more control, you can also monitor in a loop:
# while monitor.is_running():
#     time.sleep(0.5)
#     # Do other work while monitoring continues in background...

Function Decorator

import denet

# Profile a function with the decorator
@denet.profile(
    base_interval_ms=100,
    max_interval_ms=1000,
    output_file="profile_results.jsonl",
    store_in_memory=True     # Store samples in memory (default)
)
def expensive_calculation():
    # Long-running calculation
    result = 0
    for i in range(10_000_000):
        result += i
    return result

# Call the function and get both result and metrics
result, metrics = expensive_calculation()
print(f"Result: {result}, Collected {len(metrics)} samples")

# The decorator can also be used without parameters
@denet.profile
def simple_function():
    return sum(range(1000000))

result, metrics = simple_function()

Context Manager

import denet
import json

# Monitor a block of code
with denet.monitor(
    base_interval_ms=100,
    max_interval_ms=1000,
    output_file=None,         # Optional file output
    store_in_memory=True      # Store samples in memory (default)
) as mon:
    # Code to profile
    for i in range(5):
        # Do something CPU intensive
        result = sum(i*i for i in range(1_000_000))

# Access collected metrics after the block
samples = mon.get_samples()
print(f"Collected {len(samples)} samples")
print(f"Peak CPU usage: {max(sample['cpu_usage'] for sample in samples)}%")

# Generate and print summary
summary_json = mon.get_summary()
summary = json.loads(summary_json)
print(f"Average CPU usage: {summary['avg_cpu_usage']}%")
print(f"Peak memory: {summary['peak_mem_rss_kb']/1024:.2f} MB")

# Save samples to a file (includes metadata line in JSONL format)
mon.save_samples("metrics.jsonl", "jsonl")  # First line contains process metadata

Adaptive Sampling

Denet uses an intelligent adaptive sampling strategy to balance detail and efficiency:

  1. First second: Samples at the base interval rate (fast sampling for short processes)
  2. 1-10 seconds: Gradually increases from base to max interval
  3. After 10 seconds: Uses the maximum interval rate

This approach ensures high-resolution data for short-lived processes while reducing overhead for long-running ones.

Analysis Utilities

The Python API includes utilities for analyzing metrics:

import denet
import json

# Load metrics from a file (automatically skips metadata line)
metrics = denet.load_metrics("metrics.jsonl")

# If you want to include the metadata in the results
metrics_with_metadata = denet.load_metrics("metrics.jsonl", include_metadata=True)

# Access the executable path from metadata
executable_path = metrics_with_metadata[0]["executable"]  # First item is metadata when include_metadata=True

# Aggregate metrics to reduce data size
aggregated = denet.aggregate_metrics(metrics, window_size=5, method="mean")

# Find peaks in resource usage
cpu_peaks = denet.find_peaks(metrics, field='cpu_usage', threshold=50)
print(f"Found {len(cpu_peaks)} CPU usage peaks above 50%")

# Get comprehensive resource utilization statistics
stats = denet.resource_utilization(metrics)
print(f"Average CPU: {stats['avg_cpu']}%")
print(f"Total I/O: {stats['total_io_bytes']} bytes")

# Convert between formats
csv_data = denet.convert_format(metrics, to_format="csv")
with open("metrics.csv", "w") as f:
    f.write(csv_data)

# Save metrics with custom options
denet.save_metrics(metrics, "data.jsonl", format="jsonl", include_metadata=True)

# Analyze process tree patterns
tree_analysis = denet.process_tree_analysis(metrics)

# Example: Analyze CPU usage from multi-process workload
# See scripts/analyze_cpu.py for detailed CPU analysis example

Development

For detailed developer documentation, including project structure, development workflow, testing, and release process, see Developer Documentation.

License

GPL-3

Acknowledgements

  • sysinfo - Rust library for system information
  • PyO3 - Rust bindings for Python

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

denet-0.3.1.tar.gz (167.0 kB view details)

Uploaded Source

Built Distribution

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

denet-0.3.1-cp312-cp312-manylinux_2_34_x86_64.whl (494.3 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ x86-64

File details

Details for the file denet-0.3.1.tar.gz.

File metadata

  • Download URL: denet-0.3.1.tar.gz
  • Upload date:
  • Size: 167.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.8.6

File hashes

Hashes for denet-0.3.1.tar.gz
Algorithm Hash digest
SHA256 5c66d863ac421ec2c8b62e6049c693fdae98cb21e67f9a12d1a1019d04821b99
MD5 22fcb84a3063b52562c803b97526d9a6
BLAKE2b-256 e3fddda080ffa977b27bf4d26a8db114acdb5b21eb0a4f8f154fccd44a96f257

See more details on using hashes here.

File details

Details for the file denet-0.3.1-cp312-cp312-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for denet-0.3.1-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 517dfce22ce9a84f425d2418cc59476d7b66222f2b7d1953cbda679e5bc146df
MD5 789471021b708685862388555e399cc0
BLAKE2b-256 c8bbe245633b74078913d4b1c2d12c90617d74cc74aca6c26136578161b3bb3b

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