OshiMetricsProvider.java
package com.guinetik.hexafun.examples.sysmon;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.software.os.OSFileStore;
import java.util.List;
/**
* Cross-platform metrics provider using OSHI library.
*
* <p>OSHI (Operating System and Hardware Information) provides native
* access to system metrics on Windows, Linux, macOS, and other platforms
* without JNI dependencies.</p>
*
* <p>This implementation includes WSL compatibility fixes.</p>
*/
public class OshiMetricsProvider implements MetricsProvider {
private final SystemInfo si = new SystemInfo();
private final CentralProcessor cpu = si.getHardware().getProcessor();
private final GlobalMemory memory = si.getHardware().getMemory();
private long[] prevTicks;
public OshiMetricsProvider() {
// Prime the CPU tick counter - first reading needs baseline
prevTicks = cpu.getSystemCpuLoadTicks();
try {
Thread.sleep(100); // Brief pause to get meaningful delta
} catch (InterruptedException ignored) {}
prevTicks = cpu.getSystemCpuLoadTicks();
}
@Override
public double getCpuUsage() {
double load = cpu.getSystemCpuLoadBetweenTicks(prevTicks) * 100;
prevTicks = cpu.getSystemCpuLoadTicks();
return Math.max(0, Math.min(100, load)); // Clamp to 0-100
}
@Override
public double getMemoryUsage() {
long total = memory.getTotal();
long available = memory.getAvailable();
if (total <= 0) return 0;
return ((double) (total - available) / total) * 100.0;
}
@Override
public double getDiskUsage() {
var fs = si.getOperatingSystem().getFileSystem();
List<OSFileStore> stores = fs.getFileStores();
if (stores.isEmpty()) return 0;
// Find the best disk: prefer root "/" or "C:" over virtual mounts
OSFileStore best = stores.get(0);
long bestSize = 0;
for (OSFileStore store : stores) {
String mount = store.getMount();
long total = store.getTotalSpace();
// Skip virtual/empty filesystems
if (total <= 0) continue;
// Prefer root mounts
if ("/".equals(mount) || mount.matches("[A-Z]:\\\\")) {
best = store;
break;
}
// Otherwise pick the largest real filesystem
if (total > bestSize && !mount.startsWith("/snap") && !mount.startsWith("/boot")) {
best = store;
bestSize = total;
}
}
long total = best.getTotalSpace();
long usable = best.getUsableSpace();
if (total <= 0) return 0;
return ((double) (total - usable) / total) * 100.0;
}
}