Enhance disk usage retrieval with multiple fallbacks for Windows compatibility

- Implemented a new method `_get_disk_usage_safe` in `PLCDataStreamer` to safely retrieve disk usage information using `psutil` and `shutil` with fallbacks for different scenarios.
- Updated the disk usage calculation logic to handle potential errors and log warnings when disk usage retrieval fails.
- Modified the `system_state.json` to reorder active datasets and add a new `plotjuggler_path` entry.
- Added a comprehensive test script `test_disk_space.py` to validate the disk space calculation functionality via the API.
This commit is contained in:
Miguel 2025-08-22 16:04:39 +02:00
parent 6302acfc0f
commit aa75a46d84
4 changed files with 2432 additions and 3823 deletions

File diff suppressed because it is too large Load Diff

View File

@ -598,7 +598,12 @@ class PLCDataStreamer:
os.makedirs(records_path)
# Get disk usage for the drive where records are stored
usage = psutil.disk_usage(os.path.abspath(records_path))
# Use multiple fallback methods for Windows compatibility
usage = self._get_disk_usage_safe(records_path)
if usage is None:
if hasattr(self, "logger"):
self.logger.warning("Could not get disk usage information")
return None
# Calculate average CSV file size (estimate based on active datasets)
avg_file_size_per_hour = self._estimate_csv_size_per_hour()
@ -633,6 +638,63 @@ class PLCDataStreamer:
self.logger.error(f"Error calculating disk space: {e}")
return None
def _get_disk_usage_safe(self, path):
"""Safely get disk usage with Windows compatibility fallbacks"""
import shutil
from collections import namedtuple
DiskUsage = namedtuple("DiskUsage", ["total", "used", "free", "percent"])
try:
# Method 1: Try psutil with absolute path
abs_path = os.path.abspath(path)
usage = psutil.disk_usage(abs_path)
return DiskUsage(
total=usage.total,
used=usage.used,
free=usage.free,
percent=round((usage.used / usage.total) * 100, 1),
)
except (SystemError, OSError, Exception) as e:
if hasattr(self, "logger"):
self.logger.warning(f"psutil.disk_usage failed for {path}: {e}")
try:
# Method 2: Try psutil with drive root
drive = os.path.splitdrive(os.path.abspath(path))[0]
if drive:
drive_root = drive + os.sep # e.g., "D:\"
if hasattr(self, "logger"):
self.logger.info(f"Trying psutil with drive root: {drive_root}")
usage = psutil.disk_usage(drive_root)
return DiskUsage(
total=usage.total,
used=usage.used,
free=usage.free,
percent=round((usage.used / usage.total) * 100, 1),
)
except Exception as e2:
if hasattr(self, "logger"):
self.logger.warning(
f"psutil.disk_usage with drive root failed: {e2}"
)
try:
# Method 3: Use shutil.disk_usage (Python 3.3+)
if hasattr(self, "logger"):
self.logger.info("Trying shutil.disk_usage as fallback")
total, used, free = shutil.disk_usage(path)
return DiskUsage(
total=total,
used=used,
free=free,
percent=round((used / total) * 100, 1),
)
except Exception as e3:
if hasattr(self, "logger"):
self.logger.error(f"All disk usage methods failed: {e3}")
return None
def _estimate_csv_size_per_hour(self) -> float:
"""Estimate CSV file size per hour based on active datasets and variables"""
try:

View File

@ -4,10 +4,11 @@
"should_stream": false,
"active_datasets": [
"Fast",
"Test",
"DAR"
"DAR",
"Test"
]
},
"auto_recovery_enabled": true,
"last_update": "2025-08-22T15:01:09.609437"
"last_update": "2025-08-22T16:03:42.919215",
"plotjuggler_path": "C:\\Program Files\\PlotJuggler\\plotjuggler.exe"
}

72
test_disk_space.py Normal file
View File

@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""
Test script to validate the disk space calculation fix
"""
import requests
import json
import time
def test_disk_space_api():
"""Test the /api/status endpoint to see if disk_space_info works"""
url = "http://localhost:5050/api/status"
try:
print("🔍 Testing disk space calculation...")
# Make the API request
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
# Check if disk_space_info exists and is valid
disk_info = data.get("disk_space_info")
if disk_info is not None:
print("✅ Disk space information retrieved successfully!")
print(f"📁 Free space: {disk_info.get('free_space', 'N/A')}")
print(f"📊 Total space: {disk_info.get('total_space', 'N/A')}")
print(f"💾 Used space: {disk_info.get('used_space', 'N/A')}")
print(f"📈 Percent used: {disk_info.get('percent_used', 'N/A')}%")
print(
f"⏱️ Recording time left: {disk_info.get('recording_time_left', 'N/A')}"
)
print(
f"📝 Avg file size per hour: {disk_info.get('avg_file_size_per_hour', 'N/A')}"
)
return True
else:
print("❌ disk_space_info is null - error occurred during calculation")
return False
else:
print(f"❌ HTTP Error: {response.status_code}")
print(response.text)
return False
except requests.exceptions.RequestException as e:
print(f"❌ Request failed: {e}")
return False
except Exception as e:
print(f"❌ Unexpected error: {e}")
return False
if __name__ == "__main__":
print("🚀 Testing disk space calculation fix...")
print("=" * 50)
# Wait a bit for server to be ready
time.sleep(2)
success = test_disk_space_api()
print("=" * 50)
if success:
print("✅ Test PASSED - Disk space calculation is working!")
else:
print("❌ Test FAILED - Disk space calculation has issues")