Aplikasi desktop pemantau sumber daya sistem secara real-time: CPU (total + per-core), RAM, Disk (per-partisi), dan Jaringan (RX/TX). Dibangun dengan arsitektur berlapis (Layered Architecture) untuk memenuhi syarat mata kuliah Pemrograman Berorientasi Objek (Studi Kasus 5).
- Bahasa: Go (Golang) — statically-typed & compiled
- GUI Framework: Fyne v2 (cross-platform, punya canvas untuk chart kustom)
- OS Metrics: gopsutil v3 (
cpu,mem,disk,net,process)
Dikembangkan & diuji di Windows 11. Karena library gopsutil & Fyne cross-platform, kode juga dapat dikompilasi di Linux/macOS, namun verifikasi resmi hanya pada Windows (sesuai catatan spesifikasi: single-OS diperbolehkan).
- Monitoring real-time (sampling tiap ~1–2 detik):
- CPU: persentase total + beban tiap logical core (progress bar per-core)
- RAM: terpakai (GB) / total / persentase
- Disk: penggunaan tiap partisi (terpakai / total / persentase)
- Network: throughput download (RX) & upload (TX) dalam KB/s
- Live chart garis CPU & RAM (60 detik terakhir, ring buffer, update halus).
- Process list: PID, nama, CPU%, RAM% — dapat di-sort dengan klik header kolom (PID/Nama/CPU/RAM, klik lagi untuk balik arah naik/turun) & refresh tiap 3 detik.
- Alert system:
- Buat aturan dari UI (metrik, threshold %, durasi detik) → contoh: "CPU > 90% selama 30 detik".
- Aturan tersimpan di
alerts.jsondan tetap aktif setelah aplikasi di-restart. - Notifikasi sistem saat aturan terpenuhi.
- Riwayat alert persisten di
alert_history.json(tetap ada setelah restart). - Hapus aturan dari UI.
- Export riwayat metrik (CPU, RAM, Disk, Network) ke CSV dengan pilihan rentang waktu (1/5/15 menit atau semua).
Scope sengaja dibatasi pada fitur MVP sesuai spesifikasi; stretch goals belum dikerjakan.
cmd/ → presentation entrypoint (package main)
├─ main.go → wiring dependency + rakit tab + jalankan app (ramping)
├─ dashboard.go → buildDashboardTab (metric cards, chart, disk, export)
├─ process.go → buildProcessTab (tabel proses + sort klik header)
├─ alerts.go → buildAlertTab (form aturan, daftar aktif, log)
└─ monitoring.go → startMonitoring (goroutine update UI berkala)
internal/
├─ apperr/ → custom error handling
│ └─ errors.go → MetricError, StorageError (Unwrap) + sentinel errors
├─ models/ → struktur data inti (tanpa dependensi eksternal)
│ ├─ metric.go → SystemMetric, DiskPartition, ProcessStat
│ ├─ alert.go → AlertRule
│ ├─ ring_buffer.go → RingBuffer (60 sampel terakhir untuk chart)
│ └─ history.go → MetricSample, MetricHistory (riwayat untuk export)
├─ repository/ → abstraksi akses OS, dipecah per metrik
│ ├─ system_monitor.go → SystemMonitor (interface) + aggregator (menyusun 5 repo)
│ ├─ cpu/ → CPURepository + cpuMonitor
│ ├─ memory/ → MemoryRepository + memoryMonitor
│ ├─ disk/ → DiskRepository + diskMonitor
│ ├─ network/ → NetworkRepository + networkMonitor (stateful)
│ └─ process/ → ProcessRepository + processMonitor
├─ services/ → business logic murni
│ ├─ alert_engine.go → AlertEngine (evaluasi rule, persistensi, notifikasi)
│ └─ exporter.go → Exporter (metric → CSV)
└─ ui/ → komponen presentasi Fyne kustom
├─ chart.go → SystemChart (line chart)
├─ process_table.go → ProcessTable (sort klik header)
├─ core_view.go → CPUCoreView (bar per-core)
└─ disk_view.go → DiskView (bar per-partisi)
Penerapan prinsip OOP:
- Encapsulation: field privat (
size,breachSince,historyPath,lastNetStat,mu) hanya diakses lewat method; akses concurrent dilindungisync.Mutex. - Abstraction: tiap metrik punya interface sendiri (
CPURepository,MemoryRepository,DiskRepository,NetworkRepository,ProcessRepository) yang menyembunyikan detail gopsutil; UI & service hanya tahuSystemMetric/ProcessStat. - Polymorphism:
SystemMonitorbergantung pada interface repo (bukan implementasi konkret), jadi implementasi gopsutil bisa ditukar (mis. mock untuk testing) tanpa mengubah pemanggil. - Composition:
systemMonitorImplmenyusun kelima repository sebagai dependency lalu menggabungkan hasilnya menjadiSystemMetric(Go mengutamakan komposisi daripada inheritance klasik). - Custom error handling: package
apperrmembungkus error OS/file (MetricError,StorageErrordenganUnwrap()) plus sentinel (ErrNoNetworkInterface,ErrNoDiskPartition) yang dapat diperiksa viaerrors.Is— mis. adapter jaringan disconnect ditangani non-fatal. - Separation of concerns: model ⇄ repository ⇄ service ⇄ UI tidak saling bocor. Presentation layer (
cmd/) dipecah per-tab (buildDashboardTab,buildProcessTab,buildAlertTab);main.gohanya merakit, loop update dipusatkan distartMonitoring. Widget yang di-refresh berkala dibungkus structdashboardUIagar dependensinya eksplisit.
- Go 1.23+ (dikembangkan dengan 1.26) — https://go.dev/dl/
- C compiler (Fyne butuh CGO untuk render GUI):
- Windows: MinGW-w64 (mis. via MSYS2) — pastikan
gccada diPATH. - Linux:
sudo apt install build-essential libgl1-mesa-dev xorg-dev - macOS: Xcode Command Line Tools (
xcode-select --install).
- Windows: MinGW-w64 (mis. via MSYS2) — pastikan
# 1. Clone repositori
git clone <url-repo>
cd SysMON
# 2. Unduh dependensi
go mod tidy
# 3. Jalankan langsung
go run ./cmd
# (opsional) build menjadi executable
go build -o sysmon ./cmd
./sysmon # Windows: sysmon.exeFile berikut dibuat otomatis di direktori kerja dan dimuat kembali saat aplikasi dijalankan lagi:
alerts.json— aturan alert (disimpan saat tambah/hapus aturan).alert_history.json— riwayat alert yang pernah ter-trigger.
classDiagram
%% ===== Layer Models =====
class SystemMetric {
+float64 CPUUsage
+[]float64 CPUPerCore
+float64 RAMUsage
+float64 RAMUsedGB
+float64 RAMTotalGB
+float64 DiskUsage
+float64 NetRXSpeed
+float64 NetTXSpeed
+[]DiskPartition Disks
}
class DiskPartition {
+string Mountpoint
+float64 UsedPercent
+float64 UsedGB
+float64 TotalGB
}
class ProcessStat {
+int32 PID
+string Name
+float64 CPUUsage
+float32 RAMUsage
}
class AlertRule {
+string Metric
+float64 Threshold
+int Duration
}
class RingBuffer {
-[]float64 Data
-int size
+Add(value float64)
}
class MetricSample {
+time.Time Time
+float64 CPUUsage
+float64 RAMUsage
+float64 DiskUsage
+float64 NetRXSpeed
+float64 NetTXSpeed
}
class MetricHistory {
-[]MetricSample samples
-int maxSize
-sync.Mutex mu
+Add(s MetricSample)
+All() []MetricSample
+Since(d time.Duration) []MetricSample
}
%% ===== Layer Repository (dipecah per metrik) =====
class SystemMonitor {
<<interface>>
+GetCurrentMetrics() SystemMetric
+GetTopProcesses(limit int) []ProcessStat
}
class systemMonitorImpl {
-CPURepository cpuRepo
-MemoryRepository memoryRepo
-DiskRepository diskRepo
-NetworkRepository networkRepo
-ProcessRepository processRepo
+GetCurrentMetrics() SystemMetric
+GetTopProcesses(limit int) []ProcessStat
}
class CPURepository {
<<interface>>
+GetCPUUsage() float64
+GetPerCoreUsage() []float64
}
class MemoryRepository {
<<interface>>
+GetMemoryUsage() float64
+GetMemoryDetail() (float64, float64)
}
class DiskRepository {
<<interface>>
+GetDiskPartitions() []DiskPartition
+GetPrimaryDiskUsage() float64
}
class NetworkRepository {
<<interface>>
+GetNetworkSpeed() (float64, float64)
}
class ProcessRepository {
<<interface>>
+GetTopProcesses(limit int) []ProcessStat
}
class networkMonitor {
-net.IOCountersStat lastNetStat
-time.Time lastTime
-sync.Mutex mu
+GetNetworkSpeed() (float64, float64)
}
%% ===== Custom Error (apperr) =====
class MetricError {
+string Source
+string Op
+error Err
+Error() string
+Unwrap() error
}
class StorageError {
+string Op
+string Path
+error Err
+Error() string
+Unwrap() error
}
%% ===== Layer Services =====
class AlertEngine {
+[]AlertRule Rules
+[]string History
+fyne.App App
-map breachSince
-string rulesPath
-string historyPath
-sync.Mutex mu
+AddRule(rule AlertRule) error
+DeleteRule(index int) error
+GetRules() []AlertRule
+GetHistory() []string
+Evaluate(metrics SystemMetric)
-load() error
-saveRulesLocked() error
-saveHistoryLocked() error
}
class Exporter {
+ExportMetrics(writer io.Writer, samples []MetricSample) error
}
%% ===== Layer UI (Presentation) =====
class SystemChart {
+fyne.Container Container
+Update(cpuData []float64, ramData []float64, w float32, h float32)
}
class ProcessTable {
+widget.Table Table
+[]ProcessStat Data
+string SortBy
+bool SortAsc
+UpdateData(newData []ProcessStat)
-toggleSort(key string)
-sortData()
-headerText(title string, key string) string
}
class CPUCoreView {
+fyne.Container Container
-[]widget.ProgressBar bars
+Update(perCore []float64)
}
class DiskView {
+fyne.Container Container
-[]widget.ProgressBar bars
+Update(disks []DiskPartition)
}
%% ===== Relasi =====
SystemMetric *-- DiskPartition : contains
MetricHistory o-- MetricSample : stores
SystemMonitor <|.. systemMonitorImpl : implements
systemMonitorImpl o-- CPURepository : uses
systemMonitorImpl o-- MemoryRepository : uses
systemMonitorImpl o-- DiskRepository : uses
systemMonitorImpl o-- NetworkRepository : uses
systemMonitorImpl o-- ProcessRepository : uses
NetworkRepository <|.. networkMonitor : implements
systemMonitorImpl ..> SystemMetric : creates
systemMonitorImpl ..> ProcessStat : creates
networkMonitor ..> MetricError : raises
AlertEngine o-- AlertRule : manages
AlertEngine ..> SystemMetric : evaluates
AlertEngine ..> StorageError : raises
Exporter ..> MetricSample : exports
Exporter ..> StorageError : raises
SystemChart ..> RingBuffer : visualizes
ProcessTable ..> ProcessStat : displays
CPUCoreView ..> SystemMetric : displays
DiskView ..> DiskPartition : displays
note for MetricError "Tiap repo metrik membungkus error gopsutil jadi MetricError. Sentinel ErrNoNetworkInterface/ErrNoDiskPartition dicek via errors.Is."
OS uji: Windows 11. Cara menjalankan: go run ./cmd.
Tandai [x] bila lolos. Untuk verifikasi akurasi, buka Task Manager berdampingan.
- Aplikasi terbuka tanpa crash (jendela "SysMON - System Resource Monitor" muncul).
- Tiga tab tersedia: Dashboard, Processes, Alerts.
- Kartu CPU menampilkan persentase dan berubah tiap ~1–2 detik.
- Nilai CPU total sesuai Task Manager (toleransi ±5%).
- Bagian CPU Per-Core menampilkan progress bar untuk SETIAP logical core.
- Beri beban CPU (mis. buka banyak tab / proses berat) → bar per-core ikut naik.
- Kartu RAM menampilkan format
X.X GB (Y.Y%)dan sesuai Task Manager. - Kartu Net (KB/s) menampilkan
↓(RX) dan↑(TX); unduh file → angka ↓ naik. - Kartu Disk (Primary) menampilkan persentase partisi utama.
- Bagian Disk Partitions menampilkan SEMUA drive (mis. C:, D:).
- Tiap partisi menunjukkan
terpakai GB / total GB+ progress bar. - Drive optik kosong / tidak terbaca tidak membuat aplikasi error (cukup tidak tampil).
- Grafik garis menampilkan dua garis: CPU (merah) & RAM (biru) sesuai legenda.
- Garis bergerak halus ke kiri, menampilkan ~60 detik terakhir, tanpa flicker berat.
- Sumbu Y menampilkan grid 0–100%.
- Tabel menampilkan kolom PID, PROCESS NAME, CPU %, RAM %.
- Daftar refresh berkala (≥ 2 detik).
- Klik header kolom RAM %: urutan langsung berubah & panah pindah ke kolom RAM.
- Klik header kolom CPU %: urutan berdasarkan CPU lagi.
- Klik header yang sama sekali lagi: arah urutan terbalik (naik ↔ turun), panah ikut berubah.
- Klik header PID / PROCESS NAME: tabel juga bisa diurutkan berdasarkan kolom tersebut.
- Form "Buat Aturan Alert" punya: pilihan Metrik (CPU/RAM), Threshold (%), Durasi (detik).
- Input threshold kosong / > 100 / bukan angka → muncul dialog error validasi.
- Input durasi bukan angka → muncul dialog error validasi.
- Tambah aturan valid (mis. CPU > 50% selama 5 detik) → muncul "Sukses" & aturan tampil di "Aturan Aktif".
- File
alerts.jsonter-update berisi aturan baru. - Picu kondisi (beban CPU di atas threshold selama durasi) → muncul notifikasi sistem & baris baru di "Log Peringatan".
- Durasi benar-benar dihitung dalam DETIK (alert tidak trigger sebelum durasi tercapai).
- Klik tombol hapus (ikon merah) pada aturan → aturan hilang &
alerts.jsonter-update.
- Tambah 1 aturan, tutup aplikasi, jalankan lagi → aturan masih ada di "Aturan Aktif".
- File
alerts.jsonberisi aturan yang ditambahkan. - Setelah ada alert ter-trigger lalu aplikasi di-restart → Log Peringatan tetap menampilkan riwayat lama (dimuat dari
alert_history.json).
- Bagian Export Data punya dropdown Range Waktu (1 Menit / 5 Menit / 15 Menit / Semua) & tombol Export ke CSV.
- Pilih Semua → klik Export → dialog simpan muncul dengan nama default
metric_history.csv. - Simpan → muncul "Sukses (N sampel ...)"; file CSV punya kolom
Timestamp, CPU, RAM, Disk, Net RX, Net TXdan dapat dibuka di Excel/Notepad. - Pilih 1 Menit → jumlah baris yang diexport lebih sedikit daripada Semua (hanya data ~1 menit terakhir).
- Export tepat setelah aplikasi dibuka (data masih kosong/kurang) → muncul info "Belum ada data pada rentang tersebut" (tidak crash).
- Biarkan aplikasi berjalan ≥ 30 menit → tidak crash, tidak freeze.
- SysMON sendiri tidak menjadi top consumer di daftar proses.