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

  • 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
  • Process trees are monitored by default, tracking all child processes spawned by the main process

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

# Disable child process monitoring (only track the parent process)
denet --no-include-children run python multi_process_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
    include_children=True    # Monitor child processes (default True)
)

# 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']}")
print(f"Max processes: {summary['max_processes']}")

# 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}
# For more controlled execution with monitoring, use execute_with_monitoring:
import denet
import json
import subprocess

# Execute a command with monitoring and capture the result
exit_code, monitor = denet.execute_with_monitoring(
    cmd=["python", "script.py"],
    base_interval_ms=100,
    max_interval_ms=1000,
    store_in_memory=True,    # Store samples in memory
    output_file=None,        # Optional file output
    write_metadata=False,    # Write metadata as first line to output file (default False)
    include_children=True    # Monitor child processes (default True)
)

# Access collected metrics after execution
samples = monitor.get_samples()
print(f"Collected {len(samples)} samples")
print(f"Exit code: {exit_code}")

# Generate and print summary
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")

# Save samples to a file (includes metadata line in JSONL format)
monitor.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

# Direct command execution with monitoring
exit_code, monitor = denet.execute_with_monitoring(["python", "script.py"])

# Execute with metadata written to output file
exit_code, monitor = denet.execute_with_monitoring(
    cmd=["python", "script.py"],
    output_file="metrics.jsonl",
    write_metadata=True  # Includes metadata as first line: {"pid": 1234, "cmd": ["python", "script.py"], "executable": "/usr/bin/python", "t0_ms": 1625184000000}
)

# execute_with_monitoring also accepts subprocess.run arguments:
exit_code, monitor = denet.execute_with_monitoring(
    cmd=["python", "script.py"],
    base_interval_ms=100,
    store_in_memory=True,
    # Any subprocess.run arguments can be passed through:
    timeout=30,              # Process timeout in seconds
    stdout=subprocess.PIPE,  # Capture stdout
    stderr=subprocess.PIPE,  # Capture stderr
    cwd="/path/to/workdir",  # Working directory
    env={"PATH": "/usr/bin"} # Environment variables
)

# 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.4.2.tar.gz (300.7 kB view details)

Uploaded Source

Built Distributions

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

denet-0.4.2-cp312-cp312-manylinux_2_39_x86_64.whl (513.3 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.39+ x86-64

denet-0.4.2-cp312-cp312-manylinux_2_34_x86_64.whl (494.5 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ x86-64

File details

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

File metadata

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

File hashes

Hashes for denet-0.4.2.tar.gz
Algorithm Hash digest
SHA256 fdb69ee416955e4f27bd603cbc5e68ca158a7bad6911f7f71904d943305b947b
MD5 dd04e24702a8a8394f775591c1e1e619
BLAKE2b-256 3efbb3999ee4d78bbf68a9c1531bd813e8560bf8905b329e413c505f7219f80a

See more details on using hashes here.

File details

Details for the file denet-0.4.2-cp312-cp312-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for denet-0.4.2-cp312-cp312-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 20e606a8db473e8b7ad288d8ed04973c91a8291d20bcaa4fe41ff8e686b390c6
MD5 e14816de5e95f33b5e47541e9bc54d14
BLAKE2b-256 b1ad618af22d5d257f838e607de15e70f915b370c6816cb5cdd5e00208579333

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for denet-0.4.2-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 61fd0c6481cff1e437c0c961b9dc9bb3e38e3d14c6e05367aa565af0100727a8
MD5 b497b4b1e0b66da6389a0d9e72380d07
BLAKE2b-256 2285bacb1f93e52cf7e62b9a5f5345eef592bf528c08350e634d1fe19a5a9e79

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