public/Start-UnraidMonitor.ps1
|
function Start-UnraidMonitor { <# .SYNOPSIS Interactive dashboard showing server status (like 'top') but docker focused. .PARAMETER RefreshInterval Refresh rate in seconds (default 2). .PARAMETER Session Unraid session (defaults to current session). .PARAMETER LogPath Optional path to log metrics data for troubleshooting. .EXAMPLE Start-UnraidMonitor #> [CmdletBinding()] [OutputType('void')] param( [Parameter(Position = 0)] [int]$RefreshInterval = 2, [Parameter()] [UnraidSession]$Session = $script:DefaultUnraidSession, [Parameter()] [string]$LogPath ) process { try { $diskQuery = @" query MonitorDisks { array { parityCheckStatus { status progress speed } parities { name device status temp numErrors size isSpinning } disks { name device status temp numErrors size fsSize fsUsed isSpinning } caches { name device status temp numErrors size fsSize fsUsed isSpinning } } } "@ while ($true) { # Quit if 'Q' key is pressed if ($Host.UI.RawUI.KeyAvailable) { $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") if ($key.Character -eq 'q' -or $key.Character -eq 'Q') { break } } $metrics = Get-UnraidMetrics $diskResult = Invoke-UnraidQuery -Query $diskQuery -Session $Session $arrayData = $diskResult.array # Quick file logging if requested if ($LogPath) { $logEntry = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] CPU: $($metrics.CpuTotal)% | Mem: $($metrics.MemPercent)" Add-Content -Path $LogPath -Value $logEntry } Clear-Host Write-Host "top - $(Get-Date -Format 'HH:mm:ss') up (Unraid) [Press 'Q' to quit]" -ForegroundColor White Write-Host "Cpu(s): " -NoNewline -ForegroundColor Cyan Write-Host "$($metrics.CpuTotal)% Total Load" $memTotal = [UnraidSizeFix]::FormatBytes($metrics.MemTotal) $memFree = [UnraidSizeFix]::FormatBytes($metrics.MemFree) $memUsed = [UnraidSizeFix]::FormatBytes($metrics.MemUsed) Write-Host "Mem: " -NoNewline -ForegroundColor Cyan Write-Host "$memTotal total, $memFree free, $memUsed used" if ($arrayData.parityCheckStatus.status -notin @("IDLE", $null)) { $status = $arrayData.parityCheckStatus.status $progress = $arrayData.parityCheckStatus.progress $speed = $arrayData.parityCheckStatus.speed Write-Host "`nPARITY: " -NoNewline -ForegroundColor Magenta Write-Host "$status ($progress% @ $speed)" -ForegroundColor White } $header = "DEVICE".PadRight(9) + "NAME".PadRight(15) + "TEMP".PadRight(7) + "SPIN".PadRight(7) + "STATUS".PadRight(15) + "ERRORS".PadRight(10) + "USAGE" Write-Host "`n$header" -BackgroundColor Gray -ForegroundColor Black $renderRow = { param($diskItem, $isParity) $deviceName = if ($diskItem.device) { $diskItem.device } else { "-" } $diskName = if ($diskItem.name) { $diskItem.name } else { "Unknown" } if ($diskItem.isSpinning) { $spinDisplay = "UP" $tempDisplay = "$($diskItem.temp)C" } else { $spinDisplay = "DWN" $tempDisplay = "*" } $statusColor = if ($diskItem.status -ne "DISK_OK") { "Red" } elseif (! $diskItem.isSpinning) { "DarkGray" } else { "Green" } $usageDisplay = "-" if (! $isParity) { $capacity = if ($diskItem.fsSize) { $diskItem.fsSize } else { $diskItem.size } if ($capacity -gt 0) { $percentUsed = [math]::Round(($diskItem.fsUsed / $capacity) * 100, 0) $usageDisplay = "$percentUsed%" } } # Padding field a bit to keep alignment $line = $deviceName.PadRight(9) + $diskName.PadRight(15) + $tempDisplay.PadRight(7) + $spinDisplay.PadRight(7) + $diskItem.status.PadRight(15) + "$($diskItem.numErrors)".PadRight(10) + $usageDisplay Write-Host $line -ForegroundColor $statusColor } if ($arrayData.parities) { $arrayData.parities | ForEach-Object { & $renderRow $_ $true } } if ($arrayData.disks) { $arrayData.disks | ForEach-Object { & $renderRow $_ $false } } if ($arrayData.caches) { $arrayData.caches | ForEach-Object { & $renderRow $_ $false } } Start-Sleep -Seconds $RefreshInterval } } catch { # Just exit loop on error } finally { Write-Host "`nExiting Monitor..." -ForegroundColor Yellow } } } |