refactor: remove legacy Python code and optimize Rust implementation

Removed all Python source files and build configuration. Refactored Rust code to remove unused modules (exporter) and fields. Updated README to man-page format.
This commit is contained in:
m1ngsama 2025-12-18 13:12:10 +08:00
parent 1194588b7e
commit b9b2b7aced
22 changed files with 102 additions and 1192 deletions

View file

@ -14,5 +14,4 @@ serde_json = "1.0"
chrono = "0.4"
log = "0.4"
env_logger = "0.11"
csv = "1.3"
anyhow = "1.0"

View file

@ -1,6 +0,0 @@
include README.md
include LICENSE
include CHANGELOG.md
include requirements.txt
include config.json
recursive-include tests *.py

View file

@ -1,320 +0,0 @@
# Tracker (Rust Edition)
A high-performance, memory-safe system monitoring tool rewritten in Rust from the original Python implementation.
## Why Rust?
This rewrite provides several advantages over the Python version:
- **Performance**: 10-50x faster execution with minimal CPU overhead
- **Memory Safety**: Zero-cost abstractions with no garbage collection pauses
- **Reliability**: Compile-time guarantees prevent common runtime errors
- **Cross-Platform**: Consistent behavior across Linux, macOS, and Windows
- **Single Binary**: No external dependencies or runtime requirements
## Features
- **Real-time System Monitoring**
- CPU usage with accurate multi-core tracking
- Memory utilization (total, used, available, percentage)
- Disk I/O statistics across all mounted filesystems
- Network traffic analysis (bytes sent/received, packet counts)
- **Process Management**
- Top CPU-consuming processes
- Memory usage per process
- Configurable process display limit
- **Alert System**
- Configurable thresholds for CPU, memory, and disk
- Visual warnings in terminal output
- Automatic logging of all alerts
- **Logging**
- Daily rotating log files
- Structured logging with timestamps
- Multiple log levels (INFO, WARNING, ERROR)
- **Data Export**
- JSON format for programmatic access
- CSV format for spreadsheet analysis
- Automatic timestamped filenames
- **Configuration**
- JSON-based config file
- Runtime customization via CLI flags
- Sensible defaults for quick start
## Installation
### Prerequisites
- Rust 1.70 or higher (install from https://rustup.rs)
- Cargo (included with Rust)
### Building from Source
```bash
# Clone the repository
git clone https://github.com/m1ngsama/tracker.git
cd tracker
# Build release version (optimized)
cargo build --release
# The binary will be at: target/release/tracker-rs
```
### Installing System-Wide
```bash
cargo install --path .
```
## Usage
### Basic Usage
Run a single monitoring snapshot:
```bash
cargo run
# or if installed:
tracker-rs
```
### Continuous Monitoring
Run in continuous mode with 5-second intervals:
```bash
cargo run -- --continuous --interval 5
```
### Command-Line Options
```
tracker-rs [OPTIONS]
Options:
-c, --continuous Run in continuous monitoring mode
-i, --interval <SECONDS> Update interval in seconds [default: 5]
--config <FILE> Path to config file [default: config.json]
-h, --help Print help
-V, --version Print version
```
### Examples
```bash
# Monitor once and exit
tracker-rs
# Continuous monitoring every 10 seconds
tracker-rs -c -i 10
# Use custom config file
tracker-rs --config /path/to/config.json
# Continuous mode with logging enabled
RUST_LOG=info tracker-rs -c
```
## Configuration
Create or edit `config.json`:
```json
{
"update_interval": 5,
"display": {
"show_cpu": true,
"show_memory": true,
"show_disk": true,
"show_network": true,
"show_processes": true,
"show_temperatures": true
},
"process_limit": 5,
"alert_thresholds": {
"cpu_percent": 80.0,
"memory_percent": 85.0,
"disk_percent": 90.0
}
}
```
### Configuration Options
- `update_interval`: Default refresh rate (used if -i not specified)
- `display`: Toggle individual monitoring features on/off
- `process_limit`: Number of top processes to display
- `alert_thresholds`: Percentage thresholds for alerts
## Project Structure
```
tracker/
├── src/
│ ├── main.rs # Application entry point and CLI
│ ├── config.rs # Configuration management
│ ├── monitor.rs # Core system monitoring logic
│ ├── process.rs # Process tracking
│ ├── temperature.rs # Temperature sensors
│ ├── alert.rs # Alert system
│ ├── logger.rs # Logging subsystem
│ └── exporter.rs # Data export (JSON/CSV)
├── Cargo.toml # Rust dependencies
├── config.json # Default configuration
└── README-rust.md # This file
```
## Output
### Console Output
The tracker displays formatted system statistics:
```
==================================================
System Tracker - 2025-12-11 15:30:45
==================================================
CPU Usage: 35.42%
Memory: 58.21% (14.00GB / 24.00GB)
Disk: 50.40% (464.07GB / 920.86GB)
Network: Sent 4872.76MB | Recv 6633.56MB
Top Processes by CPU Usage:
PID Name CPU% Memory%
------------------------------------------------------------
1234 chrome 45.23 3.21
5678 rust-analyzer 12.45 1.85
9012 terminal 5.67 0.42
...
```
### Log Files
Daily logs are stored in `logs/tracker_YYYYMMDD.log`:
```
2025-12-11 15:30:45 - SystemTracker - INFO - CPU: 35.42%
2025-12-11 15:30:45 - SystemTracker - INFO - Memory: 58.21%
2025-12-11 15:30:45 - SystemTracker - WARNING - ALERT: CPU: CPU usage is 85.50% (threshold: 80.00%)
```
### Alerts
When thresholds are exceeded, visual alerts appear:
```
⚠️ ALERT: CPU usage is 85.50% (threshold: 80.00%)
⚠️ ALERT: Memory usage is 90.25% (threshold: 85.00%)
```
## Development
### Running Tests
```bash
cargo test
```
### Code Quality
```bash
# Check for errors
cargo check
# Lint with Clippy
cargo clippy
# Format code
cargo fmt
```
### Building for Production
```bash
# Optimized release build
cargo build --release
# Strip debug symbols for smaller binary
strip target/release/tracker-rs
```
### Debugging
Enable logging with the `RUST_LOG` environment variable:
```bash
RUST_LOG=debug cargo run
RUST_LOG=tracker_rs=trace cargo run
```
## Dependencies
Key dependencies and their purposes:
- `sysinfo` - Cross-platform system and process information
- `clap` - Command-line argument parsing
- `serde` / `serde_json` - Configuration serialization
- `chrono` - Date and time utilities
- `log` / `env_logger` - Logging framework
- `csv` - CSV file generation
- `anyhow` - Error handling
## Performance Comparison
Rust vs Python (original) on macOS M1:
| Metric | Python | Rust | Improvement |
|--------|--------|------|-------------|
| Startup Time | 250ms | 10ms | 25x faster |
| Memory Usage | 45MB | 3MB | 15x smaller |
| CPU Overhead | 2-5% | 0.1-0.5% | 10x lower |
| Binary Size | N/A | 4MB | Single binary |
## Platform Support
- **macOS**: Full support (tested on M1/M2 and Intel)
- **Linux**: Full support (tested on Ubuntu, Debian, Arch)
- **Windows**: Partial support (temperature sensors limited)
## Contributing
Contributions are welcome! Areas for improvement:
- Enhanced temperature sensor support
- GPU monitoring
- Battery status tracking
- Historical data visualization
- Web dashboard interface
## Migration from Python Version
The Rust version maintains compatibility with the Python version's:
- Configuration file format
- Log file structure
- CLI interface
Simply replace `python tracker.py` with `tracker-rs` in your scripts.
## License
MIT License - See [LICENSE](LICENSE) file
## Author
m1ngsama
## Acknowledgments
- Original Python version inspired by [psutil](https://github.com/giampaolo/psutil)
- Rust implementation built on [sysinfo](https://github.com/GuillaumeGomez/sysinfo)
- Community feedback and contributions
---
**Note**: This is a complete rewrite in Rust. While maintaining feature parity with the Python version, it introduces performance improvements and memory safety guarantees inherent to Rust.

207
README.md
View file

@ -1,137 +1,128 @@
# Tracker
tracker-rs(1) System Tracker tracker-rs(1)
A comprehensive system monitoring tool for tracking various machine health metrics and performance indicators.
NAME
tracker-rs - high-performance system monitoring tool
[![CI](https://github.com/m1ngsama/tracker/actions/workflows/ci.yml/badge.svg)](https://github.com/m1ngsama/tracker/actions/workflows/ci.yml)
[![Release](https://github.com/m1ngsama/tracker/actions/workflows/release.yml/badge.svg)](https://github.com/m1ngsama/tracker/actions/workflows/release.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
SYNOPSIS
tracker-rs [OPTIONS]
## Features
DESCRIPTION
tracker-rs is a high-performance, memory-safe system monitoring tool written in Rust.
It provides real-time statistics for CPU, memory, disk I/O, and network traffic, along
with process management and temperature monitoring.
- **CPU Monitoring**: Real-time CPU usage percentage tracking
- **Memory Utilization**: Track memory usage with detailed statistics
- **Disk I/O Statistics**: Monitor disk usage and I/O operations
- **Network Traffic Analysis**: Track network bytes sent/received
- **Process Monitoring**: View top processes by CPU usage
- **Temperature Sensors**: Monitor system temperatures (if available)
- **Alert System**: Configurable thresholds for CPU, memory, and disk alerts
- **Logging**: Automatic logging of all metrics to daily log files
- **Data Export**: Export monitoring data to JSON or CSV formats
- **Configuration**: Customizable settings via JSON config file
Designed as a drop-in replacement for the legacy Python implementation, it offers
significant performance improvements (10-50x faster execution, reduced memory usage)
while maintaining configuration compatibility.
## Installation
OPTIONS
-c, --continuous
Run in continuous monitoring mode. The tool will repeatedly display statistics
and log data based on the update interval.
### From PyPI (coming soon)
-i, --interval SECONDS
Set the update interval in seconds. Default is 5 seconds.
This option is primarily used with --continuous mode.
```bash
pip install system-tracker
```
--config FILE
Path to the configuration file. Default is "config.json".
If the file does not exist, internal defaults are used.
### From Source
-h, --help
Print help message and exit.
```bash
git clone https://github.com/m1ngsama/tracker.git
cd tracker
pip install -r requirements.txt
```
-V, --version
Print version information and exit.
## Usage
CONFIGURATION
The tool is configured via a JSON file (default: config.json).
The configuration file supports the following keys:
### Basic usage:
```bash
python tracker.py
```
update_interval (integer)
Default refresh rate in seconds (overridden by -i).
### Continuous monitoring mode:
```bash
python tracker.py --continuous --interval 5
```
display (object)
Toggle individual monitoring features on/off:
- show_cpu (boolean)
- show_memory (boolean)
- show_disk (boolean)
- show_network (boolean)
- show_processes (boolean)
- show_temperatures (boolean)
### Command line options:
- `-c, --continuous`: Run in continuous monitoring mode
- `-i, --interval`: Set update interval in seconds (default: 5)
process_limit (integer)
Number of top CPU-consuming processes to display.
## Configuration
alert_thresholds (object)
Percentage thresholds for triggering alerts:
- cpu_percent (float)
- memory_percent (float)
- disk_percent (float)
The `config.json` file allows you to customize the tracker behavior:
Example config.json:
{
"update_interval": 5,
"display": {
"show_cpu": true,
"show_memory": true,
"show_disk": true,
"show_network": true,
"show_processes": true,
"show_temperatures": true
},
"process_limit": 5,
"alert_thresholds": {
"cpu_percent": 80.0,
"memory_percent": 85.0,
"disk_percent": 90.0
}
}
```json
{
"update_interval": 5,
"display": {
"show_cpu": true,
"show_memory": true,
"show_disk": true,
"show_network": true,
"show_processes": true,
"show_temperatures": true
},
"process_limit": 5,
"alert_thresholds": {
"cpu_percent": 80,
"memory_percent": 85,
"disk_percent": 90
}
}
```
OUTPUT
tracker-rs outputs formatted system statistics to the console.
In continuous mode, it updates at the specified interval.
## Output
CPU Usage: 35.42%
Memory: 58.21% (14.00GB / 24.00GB)
Disk: 50.40% (464.07GB / 920.86GB)
Network: Sent 4872.76MB | Recv 6633.56MB
The tracker provides:
- **Console Output**: Real-time metrics displayed in the terminal
- **Log Files**: Daily logs stored in `logs/` directory
- **Alerts**: Visual and logged warnings when thresholds are exceeded
- **Export Data**: Optional data export to `exports/` directory
Top Processes by CPU Usage:
PID Name CPU% Memory%
------------------------------------------------------------
1234 chrome 45.23 3.21
## Requirements
FILES
config.json
Default configuration file location.
- Python 3.8+
- psutil
- GPUtil (for GPU monitoring)
- requests
logs/tracker_YYYYMMDD.log
Daily rotating log files containing system stats and alerts.
## Development
EXIT STATUS
0 Success.
1 Failure (e.g., invalid configuration).
### Running Tests
EXAMPLES
Run a single monitoring snapshot:
$ tracker-rs
```bash
python test_tracker.py
```
Run continuously every 2 seconds:
$ tracker-rs -c -i 2
### Project Structure
Use a custom configuration file:
$ tracker-rs --config /etc/tracker/config.json
```
tracker/
├── tracker.py # Main application
├── process_monitor.py # Process monitoring module
├── temperature_monitor.py # Temperature sensors module
├── config_manager.py # Configuration management
├── alert_system.py # Alert and threshold management
├── logger.py # Logging functionality
├── data_exporter.py # Data export utilities
├── config.json # Configuration file
└── requirements.txt # Python dependencies
```
SEE ALSO
top(1), htop(1), ps(1)
## CI/CD
BUGS
Report bugs to https://github.com/m1ngsama/tracker/issues
This project uses GitHub Actions for:
- **Continuous Integration**: Automated testing on multiple OS and Python versions
- **Automated Releases**: Automatic package building and release creation on version tags
- **Code Quality**: Linting and syntax checking
AUTHOR
m1ngsama
## Contributing
LICENSE
MIT License
Contributions are welcome! Please feel free to submit a Pull Request.
## License
MIT License - see [LICENSE](LICENSE) file for details
## Author
m1ngsama
## Acknowledgments
- Built with [psutil](https://github.com/giampaolo/psutil) for cross-platform system monitoring
v1.0.0 2025-12-18 tracker-rs(1)

View file

@ -1,58 +0,0 @@
# Migration Guide: Python to Rust
This document explains the architectural changes and benefits of the Rust rewrite.
## Architecture Changes
### Module Mapping
| Python Module | Rust Module | Changes |
|---------------|-------------|---------|
| `tracker.py` | `src/main.rs` + `src/monitor.rs` | Split into CLI and monitoring logic |
| `config_manager.py` | `src/config.rs` | Added type safety with serde |
| `process_monitor.py` | `src/process.rs` | Improved error handling |
| `temperature_monitor.py` | `src/temperature.rs` | Platform-agnostic design |
| `alert_system.py` | `src/alert.rs` | Enhanced with type-safe thresholds |
| `logger.py` | `src/logger.rs` | Zero-allocation logging |
| `data_exporter.py` | `src/exporter.rs` | Generic export with serde |
### Key Improvements
1. **Type Safety**: Compile-time guarantees prevent runtime errors
2. **Zero-Copy Operations**: Reduced memory allocations
3. **Error Handling**: Result types replace exception handling
4. **Ownership**: Rust's ownership system prevents memory leaks
5. **Concurrency**: Safe concurrent operations (future enhancement)
### API Compatibility
The Rust version maintains CLI compatibility:
```bash
# Python
python tracker.py --continuous --interval 5
# Rust
tracker-rs --continuous --interval 5
```
Configuration format remains identical for easy migration.
## Performance Benefits
- **Startup**: 25x faster cold start
- **Memory**: 15x lower memory footprint
- **CPU**: 10x lower CPU overhead during monitoring
- **Binary**: Single 4MB executable vs 45MB Python + deps
## Breaking Changes
None! The Rust version is a drop-in replacement.
## Future Enhancements
With Rust foundation, we can add:
- Async monitoring for better resource usage
- WASM compilation for browser-based monitoring
- FFI bindings for embedding in other languages
- Plugin system with dynamic loading

View file

@ -1,53 +0,0 @@
"""
Alert system for system monitoring
"""
from logger import TrackerLogger
class AlertSystem:
def __init__(self, config):
self.config = config
self.logger = TrackerLogger()
self.alert_history = []
def check_cpu_alert(self, cpu_percent):
"""Check if CPU usage exceeds threshold"""
threshold = self.config.get('alert_thresholds.cpu_percent', 80)
if cpu_percent > threshold:
message = f"CPU usage is {cpu_percent}% (threshold: {threshold}%)"
self.trigger_alert('CPU', message)
return True
return False
def check_memory_alert(self, memory_percent):
"""Check if memory usage exceeds threshold"""
threshold = self.config.get('alert_thresholds.memory_percent', 85)
if memory_percent > threshold:
message = f"Memory usage is {memory_percent}% (threshold: {threshold}%)"
self.trigger_alert('Memory', message)
return True
return False
def check_disk_alert(self, disk_percent):
"""Check if disk usage exceeds threshold"""
threshold = self.config.get('alert_thresholds.disk_percent', 90)
if disk_percent > threshold:
message = f"Disk usage is {disk_percent}% (threshold: {threshold}%)"
self.trigger_alert('Disk', message)
return True
return False
def trigger_alert(self, alert_type, message):
"""Trigger an alert"""
alert = {
'type': alert_type,
'message': message
}
self.alert_history.append(alert)
self.logger.log_alert(f"{alert_type}: {message}")
print(f"\n⚠️ ALERT: {message}")
def get_alert_history(self):
"""Get alert history"""
return self.alert_history

View file

@ -1,50 +0,0 @@
"""
Configuration management for tracker
"""
import json
import os
class Config:
def __init__(self, config_file='config.json'):
self.config_file = config_file
self.config = self.load_config()
def load_config(self):
"""Load configuration from JSON file"""
if os.path.exists(self.config_file):
with open(self.config_file, 'r') as f:
return json.load(f)
return self.get_default_config()
def get_default_config(self):
"""Return default configuration"""
return {
'update_interval': 5,
'display': {
'show_cpu': True,
'show_memory': True,
'show_disk': True,
'show_network': True,
'show_processes': True,
'show_temperatures': True
},
'process_limit': 5,
'alert_thresholds': {
'cpu_percent': 80,
'memory_percent': 85,
'disk_percent': 90
}
}
def get(self, key, default=None):
"""Get configuration value"""
keys = key.split('.')
value = self.config
for k in keys:
if isinstance(value, dict):
value = value.get(k, default)
else:
return default
return value

View file

@ -1,51 +0,0 @@
"""
Data export functionality
"""
import json
import csv
from datetime import datetime
class DataExporter:
def __init__(self, output_dir='exports'):
self.output_dir = output_dir
self._ensure_directory()
def _ensure_directory(self):
"""Ensure the output directory exists"""
import os
if not os.path.exists(self.output_dir):
os.makedirs(self.output_dir)
def export_to_json(self, data, filename=None):
"""Export data to JSON format"""
if filename is None:
filename = f"tracker_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
filepath = f"{self.output_dir}/{filename}"
try:
with open(filepath, 'w') as f:
json.dump(data, f, indent=2)
return filepath
except IOError as e:
raise IOError(f"Failed to export data to JSON: {e}")
def export_to_csv(self, data, filename=None):
"""Export data to CSV format"""
if filename is None:
filename = f"tracker_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
filepath = f"{self.output_dir}/{filename}"
try:
if isinstance(data, list) and len(data) > 0:
keys = data[0].keys()
with open(filepath, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=keys)
writer.writeheader()
writer.writerows(data)
return filepath
except IOError as e:
raise IOError(f"Failed to export data to CSV: {e}")

View file

@ -1,55 +0,0 @@
"""
Logging functionality for tracker
"""
import logging
import os
from datetime import datetime
class TrackerLogger:
def __init__(self, log_dir='logs'):
self.log_dir = log_dir
self.setup_logger()
def setup_logger(self):
"""Setup logging configuration"""
if not os.path.exists(self.log_dir):
os.makedirs(self.log_dir)
log_file = os.path.join(
self.log_dir,
f"tracker_{datetime.now().strftime('%Y%m%d')}.log"
)
# Clear any existing handlers to prevent duplicate logging
logger = logging.getLogger('SystemTracker')
logger.handlers.clear()
# Create handlers
file_handler = logging.FileHandler(log_file)
stream_handler = logging.StreamHandler()
# Create formatter and add it to handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
stream_handler.setFormatter(formatter)
# Add handlers to logger
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
logger.setLevel(logging.INFO)
self.logger = logger
def log_stats(self, stats_type, stats_data):
"""Log system statistics"""
self.logger.info(f"{stats_type}: {stats_data}")
def log_alert(self, message):
"""Log alert messages"""
self.logger.warning(f"ALERT: {message}")
def log_error(self, error_message):
"""Log error messages"""
self.logger.error(f"ERROR: {error_message}")

View file

@ -1,51 +0,0 @@
"""
Process monitoring utilities
"""
import psutil
class ProcessMonitor:
def get_top_processes(self, limit=5):
"""Get top processes by CPU usage"""
processes = []
# First collect all processes
for proc in psutil.process_iter(['pid', 'name']):
try:
# Get CPU percent with interval for more accurate reading
cpu_percent = proc.cpu_percent(interval=0.1)
memory_percent = proc.memory_percent()
processes.append({
'pid': proc.info['pid'],
'name': proc.info['name'],
'cpu_percent': cpu_percent,
'memory_percent': memory_percent
})
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
processes.sort(key=lambda x: x['cpu_percent'] or 0, reverse=True)
return processes[:limit]
def get_process_count(self):
"""Get total number of running processes"""
try:
return len(psutil.pids())
except Exception:
return 0
def display_processes(self):
"""Display top processes"""
try:
print(f"\nTop Processes by CPU Usage:")
print(f"{'PID':<10}{'Name':<30}{'CPU%':<10}{'Memory%':<10}")
print("-" * 60)
for proc in self.get_top_processes():
cpu = proc['cpu_percent'] if proc['cpu_percent'] is not None else 0
mem = proc['memory_percent'] if proc['memory_percent'] is not None else 0
print(f"{proc['pid']:<10}{proc['name']:<30}{cpu:<10.2f}{mem:<10.2f}")
print(f"\nTotal Processes: {self.get_process_count()}")
except Exception as e:
print(f"Error displaying processes: {e}")

View file

@ -1,44 +0,0 @@
[build-system]
requires = ["setuptools>=45", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "system-tracker"
version = "1.0.0"
description = "A comprehensive system monitoring tool for tracking machine health metrics"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
authors = [
{name = "m1ngsama"}
]
keywords = ["monitoring", "system", "performance", "metrics", "health-check"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Intended Audience :: System Administrators",
"Topic :: System :: Monitoring",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
dependencies = [
"psutil>=5.9.0",
"GPUtil>=1.4.0",
"requests>=2.28.0",
]
[project.urls]
Homepage = "https://github.com/m1ngsama/tracker"
Repository = "https://github.com/m1ngsama/tracker"
Issues = "https://github.com/m1ngsama/tracker/issues"
[project.scripts]
tracker = "tracker:main"
[tool.setuptools]
py-modules = ["tracker", "process_monitor", "temperature_monitor", "config_manager", "alert_system", "logger", "data_exporter"]

View file

@ -1,3 +0,0 @@
psutil>=5.9.0
GPUtil>=1.4.0
requests>=2.28.0

View file

@ -1,55 +0,0 @@
from setuptools import setup
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
with open("requirements.txt", "r", encoding="utf-8") as fh:
requirements = [line.strip() for line in fh if line.strip() and not line.startswith("#")]
setup(
name="system-tracker",
version="1.0.0",
author="m1ngsama",
author_email="",
description="A comprehensive system monitoring tool for tracking machine health metrics",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/m1ngsama/tracker",
py_modules=[
"tracker",
"process_monitor",
"temperature_monitor",
"config_manager",
"alert_system",
"logger",
"data_exporter",
],
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Intended Audience :: System Administrators",
"Topic :: System :: Monitoring",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Operating System :: OS Independent",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows",
],
python_requires=">=3.8",
install_requires=requirements,
entry_points={
"console_scripts": [
"tracker=tracker:main",
],
},
include_package_data=True,
data_files=[
("", ["config.json"]),
],
)

View file

@ -4,13 +4,6 @@ use crate::logger::TrackerLogger;
pub struct AlertSystem {
config: Config,
logger: TrackerLogger,
alert_history: Vec<Alert>,
}
#[derive(Debug, Clone)]
pub struct Alert {
pub alert_type: String,
pub message: String,
}
impl AlertSystem {
@ -18,7 +11,6 @@ impl AlertSystem {
AlertSystem {
config,
logger: TrackerLogger::default(),
alert_history: Vec::new(),
}
}
@ -53,16 +45,7 @@ impl AlertSystem {
}
fn trigger_alert(&mut self, alert_type: &str, message: &str) {
let alert = Alert {
alert_type: alert_type.to_string(),
message: message.to_string(),
};
self.alert_history.push(alert.clone());
self.logger.log_alert(&format!("{}: {}", alert_type, message));
println!("\n⚠️ ALERT: {}", message);
}
pub fn get_alert_history(&self) -> &[Alert] {
&self.alert_history
}
}
}

View file

@ -1,53 +0,0 @@
use serde::Serialize;
use std::fs;
use std::path::PathBuf;
use anyhow::Result;
use chrono::Local;
pub struct DataExporter {
output_dir: PathBuf,
}
impl DataExporter {
pub fn new(output_dir: &str) -> Self {
let output_dir = PathBuf::from(output_dir);
if !output_dir.exists() {
fs::create_dir_all(&output_dir).ok();
}
DataExporter { output_dir }
}
pub fn export_to_json<T: Serialize>(&self, data: &T, filename: Option<String>) -> Result<PathBuf> {
let filename = filename.unwrap_or_else(|| {
format!("tracker_data_{}.json", Local::now().format("%Y%m%d_%H%M%S"))
});
let filepath = self.output_dir.join(filename);
let json = serde_json::to_string_pretty(data)?;
fs::write(&filepath, json)?;
Ok(filepath)
}
pub fn export_to_csv<T: Serialize>(&self, data: &[T], filename: Option<String>) -> Result<PathBuf> {
let filename = filename.unwrap_or_else(|| {
format!("tracker_data_{}.csv", Local::now().format("%Y%m%d_%H%M%S"))
});
let filepath = self.output_dir.join(filename);
let mut wtr = csv::Writer::from_path(&filepath)?;
for record in data {
wtr.serialize(record)?;
}
wtr.flush()?;
Ok(filepath)
}
}
impl Default for DataExporter {
fn default() -> Self {
Self::new("exports")
}
}

View file

@ -43,15 +43,10 @@ impl TrackerLogger {
let alert_message = format!("ALERT: {}", message);
self.write_log("WARNING", &alert_message);
}
pub fn log_error(&self, error_message: &str) {
let error_msg = format!("ERROR: {}", error_message);
self.write_log("ERROR", &error_msg);
}
}
impl Default for TrackerLogger {
fn default() -> Self {
Self::new("logs")
}
}
}

View file

@ -8,7 +8,6 @@ mod process;
mod temperature;
mod alert;
mod logger;
mod exporter;
use config::Config;
use monitor::SystemMonitor;

View file

@ -42,7 +42,6 @@ impl SystemMonitor {
self.sys.refresh_memory();
let total = self.sys.total_memory();
let used = self.sys.used_memory();
let available = self.sys.available_memory();
let percent = if total > 0 {
(used as f32 / total as f32) * 100.0
} else {
@ -52,7 +51,6 @@ impl SystemMonitor {
MemoryInfo {
total,
used,
available,
percent,
}
}
@ -78,7 +76,6 @@ impl SystemMonitor {
DiskInfo {
total,
used,
free: available,
percent,
}
}
@ -88,21 +85,15 @@ impl SystemMonitor {
let mut bytes_sent = 0;
let mut bytes_recv = 0;
let mut packets_sent = 0;
let mut packets_recv = 0;
for (_, network) in &self.networks {
bytes_sent += network.total_transmitted();
bytes_recv += network.total_received();
packets_sent += network.total_packets_transmitted();
packets_recv += network.total_packets_received();
}
NetworkStats {
bytes_sent,
bytes_recv,
packets_sent,
packets_recv,
}
}
@ -163,7 +154,6 @@ impl SystemMonitor {
pub struct MemoryInfo {
pub total: u64,
pub used: u64,
pub available: u64,
pub percent: f32,
}
@ -171,7 +161,6 @@ pub struct MemoryInfo {
pub struct DiskInfo {
pub total: u64,
pub used: u64,
pub free: u64,
pub percent: f32,
}
@ -179,6 +168,4 @@ pub struct DiskInfo {
pub struct NetworkStats {
pub bytes_sent: u64,
pub bytes_recv: u64,
pub packets_sent: u64,
pub packets_recv: u64,
}
}

View file

@ -1,35 +0,0 @@
"""
Temperature sensor monitoring
"""
import psutil
class TemperatureMonitor:
def get_temperatures(self):
"""Get system temperatures if available"""
try:
temps = psutil.sensors_temperatures()
return temps
except AttributeError:
return None
def display_temperatures(self):
"""Display system temperatures"""
temps = self.get_temperatures()
if not temps:
print("\nTemperature sensors not available on this system")
return
print("\nSystem Temperatures:")
print(f"{'Sensor':<30}{'Current':<15}{'High':<15}{'Critical':<15}")
print("-" * 75)
for name, entries in temps.items():
for entry in entries:
label = entry.label or name
current = f"{entry.current}°C" if entry.current else "N/A"
high = f"{entry.high}°C" if entry.high else "N/A"
critical = f"{entry.critical}°C" if entry.critical else "N/A"
print(f"{label:<30}{current:<15}{high:<15}{critical:<15}")

View file

@ -1,26 +0,0 @@
#!/usr/bin/env python3
"""Test data export functionality"""
from data_exporter import DataExporter
# Test data
test_data = [
{'timestamp': '2025-11-25 15:00:00', 'cpu': 45.2, 'memory': 60.1},
{'timestamp': '2025-11-25 15:05:00', 'cpu': 52.3, 'memory': 62.5},
{'timestamp': '2025-11-25 15:10:00', 'cpu': 48.9, 'memory': 61.8}
]
exporter = DataExporter()
# Test JSON export
json_file = exporter.export_to_json(test_data)
print(f"✓ JSON export successful: {json_file}")
# Test CSV export
csv_file = exporter.export_to_csv(test_data)
print(f"✓ CSV export successful: {csv_file}")
print("\nExport directory contents:")
import os
for file in os.listdir('exports'):
print(f" - {file}")

View file

@ -1,45 +0,0 @@
"""
Unit tests for tracker functionality
"""
import unittest
from unittest.mock import Mock, patch
from tracker import SystemTracker
class TestSystemTracker(unittest.TestCase):
def setUp(self):
self.tracker = SystemTracker()
@patch('psutil.cpu_percent')
def test_get_cpu_usage(self, mock_cpu):
mock_cpu.return_value = 50.0
result = self.tracker.get_cpu_usage()
self.assertEqual(result, 50.0)
@patch('psutil.virtual_memory')
def test_get_memory_info(self, mock_mem):
mock_mem.return_value = Mock(
total=8589934592,
available=4294967296,
percent=50.0,
used=4294967296
)
result = self.tracker.get_memory_info()
self.assertEqual(result['percent'], 50.0)
self.assertEqual(result['total'], 8589934592)
@patch('psutil.disk_usage')
def test_get_disk_usage(self, mock_disk):
mock_disk.return_value = Mock(
total=1000000000000,
used=500000000000,
free=500000000000,
percent=50.0
)
result = self.tracker.get_disk_usage()
self.assertEqual(result['percent'], 50.0)
if __name__ == '__main__':
unittest.main()

View file

@ -1,139 +0,0 @@
#!/usr/bin/env python3
"""
System Tracker - Monitor machine health and performance
"""
import psutil
import time
import argparse
from datetime import datetime
from process_monitor import ProcessMonitor
from temperature_monitor import TemperatureMonitor
from config_manager import Config
from alert_system import AlertSystem
from logger import TrackerLogger
class SystemTracker:
def __init__(self, config_file='config.json'):
self.start_time = time.time()
self.config = Config(config_file)
self.process_monitor = ProcessMonitor()
self.temperature_monitor = TemperatureMonitor()
self.alert_system = AlertSystem(self.config)
self.logger = TrackerLogger()
def get_cpu_usage(self):
"""Get current CPU usage percentage"""
try:
return psutil.cpu_percent(interval=1, percpu=False)
except Exception as e:
self.logger.log_error(f"Failed to get CPU usage: {e}")
return 0.0
def get_memory_info(self):
"""Get memory usage statistics"""
try:
mem = psutil.virtual_memory()
return {
'total': mem.total,
'available': mem.available,
'percent': mem.percent,
'used': mem.used
}
except Exception as e:
self.logger.log_error(f"Failed to get memory info: {e}")
return {'total': 0, 'available': 0, 'percent': 0, 'used': 0}
def get_disk_usage(self):
"""Get disk usage statistics"""
try:
disk = psutil.disk_usage('/')
return {
'total': disk.total,
'used': disk.used,
'free': disk.free,
'percent': disk.percent
}
except Exception as e:
self.logger.log_error(f"Failed to get disk usage: {e}")
return {'total': 0, 'used': 0, 'free': 0, 'percent': 0}
def get_network_stats(self):
"""Get network I/O statistics"""
try:
net = psutil.net_io_counters()
return {
'bytes_sent': net.bytes_sent,
'bytes_recv': net.bytes_recv,
'packets_sent': net.packets_sent,
'packets_recv': net.packets_recv
}
except Exception as e:
self.logger.log_error(f"Failed to get network stats: {e}")
return {'bytes_sent': 0, 'bytes_recv': 0, 'packets_sent': 0, 'packets_recv': 0}
def display_stats(self):
"""Display all system statistics"""
print(f"\n{'='*50}")
print(f"System Tracker - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'='*50}\n")
# CPU monitoring
if self.config.get('display.show_cpu', True):
cpu_usage = self.get_cpu_usage()
print(f"CPU Usage: {cpu_usage}%")
self.logger.log_stats('CPU', f"{cpu_usage}%")
self.alert_system.check_cpu_alert(cpu_usage)
# Memory monitoring
if self.config.get('display.show_memory', True):
mem = self.get_memory_info()
print(f"Memory: {mem['percent']}% ({mem['used'] / (1024**3):.2f}GB / {mem['total'] / (1024**3):.2f}GB)")
self.logger.log_stats('Memory', f"{mem['percent']}%")
self.alert_system.check_memory_alert(mem['percent'])
# Disk monitoring
if self.config.get('display.show_disk', True):
disk = self.get_disk_usage()
print(f"Disk: {disk['percent']}% ({disk['used'] / (1024**3):.2f}GB / {disk['total'] / (1024**3):.2f}GB)")
self.logger.log_stats('Disk', f"{disk['percent']}%")
self.alert_system.check_disk_alert(disk['percent'])
# Network monitoring
if self.config.get('display.show_network', True):
net = self.get_network_stats()
print(f"Network: Sent {net['bytes_sent'] / (1024**2):.2f}MB | Recv {net['bytes_recv'] / (1024**2):.2f}MB")
self.logger.log_stats('Network', f"Sent: {net['bytes_sent']} Recv: {net['bytes_recv']}")
# Process monitoring
if self.config.get('display.show_processes', True):
self.process_monitor.display_processes()
# Temperature monitoring
if self.config.get('display.show_temperatures', True):
self.temperature_monitor.display_temperatures()
def main():
"""Main entry point for the tracker application"""
parser = argparse.ArgumentParser(description='System Tracker - Monitor machine health')
parser.add_argument('-c', '--continuous', action='store_true', help='Run continuously')
parser.add_argument('-i', '--interval', type=int, default=5, help='Update interval in seconds')
args = parser.parse_args()
tracker = SystemTracker()
if args.continuous:
try:
while True:
tracker.display_stats()
time.sleep(args.interval)
except KeyboardInterrupt:
print("\n\nTracker stopped by user")
else:
tracker.display_stats()
if __name__ == "__main__":
main()