mirror of
https://github.com/m1ngsama/tracker.git
synced 2025-12-24 10:51:43 +00:00
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:
parent
1194588b7e
commit
b9b2b7aced
22 changed files with 102 additions and 1192 deletions
|
|
@ -14,5 +14,4 @@ serde_json = "1.0"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
csv = "1.3"
|
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
include README.md
|
|
||||||
include LICENSE
|
|
||||||
include CHANGELOG.md
|
|
||||||
include requirements.txt
|
|
||||||
include config.json
|
|
||||||
recursive-include tests *.py
|
|
||||||
320
README-rust.md
320
README-rust.md
|
|
@ -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
207
README.md
|
|
@ -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
|
||||||
|
|
||||||
[](https://github.com/m1ngsama/tracker/actions/workflows/ci.yml)
|
SYNOPSIS
|
||||||
[](https://github.com/m1ngsama/tracker/actions/workflows/release.yml)
|
tracker-rs [OPTIONS]
|
||||||
[](https://opensource.org/licenses/MIT)
|
|
||||||
|
|
||||||
## 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
|
Designed as a drop-in replacement for the legacy Python implementation, it offers
|
||||||
- **Memory Utilization**: Track memory usage with detailed statistics
|
significant performance improvements (10-50x faster execution, reduced memory usage)
|
||||||
- **Disk I/O Statistics**: Monitor disk usage and I/O operations
|
while maintaining configuration compatibility.
|
||||||
- **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
|
|
||||||
|
|
||||||
## 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
|
--config FILE
|
||||||
pip install system-tracker
|
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
|
-V, --version
|
||||||
git clone https://github.com/m1ngsama/tracker.git
|
Print version information and exit.
|
||||||
cd tracker
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
CONFIGURATION
|
||||||
|
The tool is configured via a JSON file (default: config.json).
|
||||||
|
The configuration file supports the following keys:
|
||||||
|
|
||||||
### Basic usage:
|
update_interval (integer)
|
||||||
```bash
|
Default refresh rate in seconds (overridden by -i).
|
||||||
python tracker.py
|
|
||||||
```
|
|
||||||
|
|
||||||
### Continuous monitoring mode:
|
display (object)
|
||||||
```bash
|
Toggle individual monitoring features on/off:
|
||||||
python tracker.py --continuous --interval 5
|
- show_cpu (boolean)
|
||||||
```
|
- show_memory (boolean)
|
||||||
|
- show_disk (boolean)
|
||||||
|
- show_network (boolean)
|
||||||
|
- show_processes (boolean)
|
||||||
|
- show_temperatures (boolean)
|
||||||
|
|
||||||
### Command line options:
|
process_limit (integer)
|
||||||
- `-c, --continuous`: Run in continuous monitoring mode
|
Number of top CPU-consuming processes to display.
|
||||||
- `-i, --interval`: Set update interval in seconds (default: 5)
|
|
||||||
|
|
||||||
## 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
|
OUTPUT
|
||||||
{
|
tracker-rs outputs formatted system statistics to the console.
|
||||||
"update_interval": 5,
|
In continuous mode, it updates at the specified interval.
|
||||||
"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
|
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:
|
Top Processes by CPU Usage:
|
||||||
- **Console Output**: Real-time metrics displayed in the terminal
|
PID Name CPU% Memory%
|
||||||
- **Log Files**: Daily logs stored in `logs/` directory
|
------------------------------------------------------------
|
||||||
- **Alerts**: Visual and logged warnings when thresholds are exceeded
|
1234 chrome 45.23 3.21
|
||||||
- **Export Data**: Optional data export to `exports/` directory
|
|
||||||
|
|
||||||
## Requirements
|
FILES
|
||||||
|
config.json
|
||||||
|
Default configuration file location.
|
||||||
|
|
||||||
- Python 3.8+
|
logs/tracker_YYYYMMDD.log
|
||||||
- psutil
|
Daily rotating log files containing system stats and alerts.
|
||||||
- GPUtil (for GPU monitoring)
|
|
||||||
- requests
|
|
||||||
|
|
||||||
## Development
|
EXIT STATUS
|
||||||
|
0 Success.
|
||||||
|
1 Failure (e.g., invalid configuration).
|
||||||
|
|
||||||
### Running Tests
|
EXAMPLES
|
||||||
|
Run a single monitoring snapshot:
|
||||||
|
$ tracker-rs
|
||||||
|
|
||||||
```bash
|
Run continuously every 2 seconds:
|
||||||
python test_tracker.py
|
$ tracker-rs -c -i 2
|
||||||
```
|
|
||||||
|
|
||||||
### Project Structure
|
Use a custom configuration file:
|
||||||
|
$ tracker-rs --config /etc/tracker/config.json
|
||||||
|
|
||||||
```
|
SEE ALSO
|
||||||
tracker/
|
top(1), htop(1), ps(1)
|
||||||
├── 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## CI/CD
|
BUGS
|
||||||
|
Report bugs to https://github.com/m1ngsama/tracker/issues
|
||||||
|
|
||||||
This project uses GitHub Actions for:
|
AUTHOR
|
||||||
- **Continuous Integration**: Automated testing on multiple OS and Python versions
|
m1ngsama
|
||||||
- **Automated Releases**: Automatic package building and release creation on version tags
|
|
||||||
- **Code Quality**: Linting and syntax checking
|
|
||||||
|
|
||||||
## Contributing
|
LICENSE
|
||||||
|
MIT License
|
||||||
|
|
||||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
v1.0.0 2025-12-18 tracker-rs(1)
|
||||||
|
|
||||||
## 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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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}")
|
|
||||||
55
logger.py
55
logger.py
|
|
@ -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}")
|
|
||||||
|
|
@ -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}")
|
|
||||||
|
|
@ -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"]
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
psutil>=5.9.0
|
|
||||||
GPUtil>=1.4.0
|
|
||||||
requests>=2.28.0
|
|
||||||
55
setup.py
55
setup.py
|
|
@ -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"]),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
19
src/alert.rs
19
src/alert.rs
|
|
@ -4,13 +4,6 @@ use crate::logger::TrackerLogger;
|
||||||
pub struct AlertSystem {
|
pub struct AlertSystem {
|
||||||
config: Config,
|
config: Config,
|
||||||
logger: TrackerLogger,
|
logger: TrackerLogger,
|
||||||
alert_history: Vec<Alert>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Alert {
|
|
||||||
pub alert_type: String,
|
|
||||||
pub message: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlertSystem {
|
impl AlertSystem {
|
||||||
|
|
@ -18,7 +11,6 @@ impl AlertSystem {
|
||||||
AlertSystem {
|
AlertSystem {
|
||||||
config,
|
config,
|
||||||
logger: TrackerLogger::default(),
|
logger: TrackerLogger::default(),
|
||||||
alert_history: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,16 +45,7 @@ impl AlertSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trigger_alert(&mut self, alert_type: &str, message: &str) {
|
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));
|
self.logger.log_alert(&format!("{}: {}", alert_type, message));
|
||||||
println!("\n⚠️ ALERT: {}", message);
|
println!("\n⚠️ ALERT: {}", message);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pub fn get_alert_history(&self) -> &[Alert] {
|
|
||||||
&self.alert_history
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -43,15 +43,10 @@ impl TrackerLogger {
|
||||||
let alert_message = format!("ALERT: {}", message);
|
let alert_message = format!("ALERT: {}", message);
|
||||||
self.write_log("WARNING", &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 {
|
impl Default for TrackerLogger {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new("logs")
|
Self::new("logs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,6 @@ mod process;
|
||||||
mod temperature;
|
mod temperature;
|
||||||
mod alert;
|
mod alert;
|
||||||
mod logger;
|
mod logger;
|
||||||
mod exporter;
|
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use monitor::SystemMonitor;
|
use monitor::SystemMonitor;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ impl SystemMonitor {
|
||||||
self.sys.refresh_memory();
|
self.sys.refresh_memory();
|
||||||
let total = self.sys.total_memory();
|
let total = self.sys.total_memory();
|
||||||
let used = self.sys.used_memory();
|
let used = self.sys.used_memory();
|
||||||
let available = self.sys.available_memory();
|
|
||||||
let percent = if total > 0 {
|
let percent = if total > 0 {
|
||||||
(used as f32 / total as f32) * 100.0
|
(used as f32 / total as f32) * 100.0
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -52,7 +51,6 @@ impl SystemMonitor {
|
||||||
MemoryInfo {
|
MemoryInfo {
|
||||||
total,
|
total,
|
||||||
used,
|
used,
|
||||||
available,
|
|
||||||
percent,
|
percent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -78,7 +76,6 @@ impl SystemMonitor {
|
||||||
DiskInfo {
|
DiskInfo {
|
||||||
total,
|
total,
|
||||||
used,
|
used,
|
||||||
free: available,
|
|
||||||
percent,
|
percent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -88,21 +85,15 @@ impl SystemMonitor {
|
||||||
|
|
||||||
let mut bytes_sent = 0;
|
let mut bytes_sent = 0;
|
||||||
let mut bytes_recv = 0;
|
let mut bytes_recv = 0;
|
||||||
let mut packets_sent = 0;
|
|
||||||
let mut packets_recv = 0;
|
|
||||||
|
|
||||||
for (_, network) in &self.networks {
|
for (_, network) in &self.networks {
|
||||||
bytes_sent += network.total_transmitted();
|
bytes_sent += network.total_transmitted();
|
||||||
bytes_recv += network.total_received();
|
bytes_recv += network.total_received();
|
||||||
packets_sent += network.total_packets_transmitted();
|
|
||||||
packets_recv += network.total_packets_received();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkStats {
|
NetworkStats {
|
||||||
bytes_sent,
|
bytes_sent,
|
||||||
bytes_recv,
|
bytes_recv,
|
||||||
packets_sent,
|
|
||||||
packets_recv,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,7 +154,6 @@ impl SystemMonitor {
|
||||||
pub struct MemoryInfo {
|
pub struct MemoryInfo {
|
||||||
pub total: u64,
|
pub total: u64,
|
||||||
pub used: u64,
|
pub used: u64,
|
||||||
pub available: u64,
|
|
||||||
pub percent: f32,
|
pub percent: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,7 +161,6 @@ pub struct MemoryInfo {
|
||||||
pub struct DiskInfo {
|
pub struct DiskInfo {
|
||||||
pub total: u64,
|
pub total: u64,
|
||||||
pub used: u64,
|
pub used: u64,
|
||||||
pub free: u64,
|
|
||||||
pub percent: f32,
|
pub percent: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,6 +168,4 @@ pub struct DiskInfo {
|
||||||
pub struct NetworkStats {
|
pub struct NetworkStats {
|
||||||
pub bytes_sent: u64,
|
pub bytes_sent: u64,
|
||||||
pub bytes_recv: u64,
|
pub bytes_recv: u64,
|
||||||
pub packets_sent: u64,
|
}
|
||||||
pub packets_recv: u64,
|
|
||||||
}
|
|
||||||
|
|
@ -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}")
|
|
||||||
|
|
@ -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}")
|
|
||||||
|
|
@ -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()
|
|
||||||
139
tracker.py
139
tracker.py
|
|
@ -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()
|
|
||||||
Loading…
Reference in a new issue