Private/Start-MetricWatcher.ps1
|
Function Start-MetricWatcher { <# .SYNOPSIS Continuously redraws the output of a metrics command in the terminal's alternate screen buffer, refreshing on a fixed interval until Ctrl+C is pressed. This helper is used by Get-KubePodMetric and Get-KubeNodeMetric when -Watch is specified. It always restores the main screen buffer, cursor and Ctrl+C handling on exit, including when the pipeline is stopped or an error is thrown. .EXAMPLE Start-MetricWatcher -MetricCommand 'Get-PodMetrics' -MetricParameters @{ Namespace = 'default' } -Title "Pod metrics in namespace 'default'" # Shows a live table of pod usage in the default namespace, refreshing twice a second. .EXAMPLE Get-KubeNodeMetric -Watch -RefreshSeconds 2 # Internally starts the watcher and shows node usage, refreshing every two seconds. #> [CmdletBinding()] param( [Parameter(Mandatory=$True, Position=0, HelpMessage='The name of the command that retrieves the metrics on each refresh.')] [string]$MetricCommand, [Parameter(Mandatory=$False, Position=1, HelpMessage='The parameters to splat to the metrics command on each refresh.')] [hashtable]$MetricParameters = @{}, [Parameter(Mandatory=$True, Position=2, HelpMessage='The title shown at the start of the header line.')] [string]$Title, [Parameter(Mandatory=$False, Position=3, HelpMessage='The number of seconds between refreshes.')] [double]$RefreshSeconds = 0.5 ) $Escape = [char]27 $ListenForKeys = [Console]::IsInputRedirected -eq $False If($ListenForKeys) { $PreviousTreatControlCAsInput = [Console]::TreatControlCAsInput [Console]::TreatControlCAsInput = $True } # Switch to the alternate screen buffer and hide the cursor. [Console]::Write("$Escape[?1049h$Escape[?25l") Try { While($True) { Try { $Metrics = & $MetricCommand @MetricParameters -ErrorAction Stop $Body = ($Metrics | Format-Table | Out-String -Width ([Console]::WindowWidth)).Trim("`r", "`n") If([string]::IsNullOrWhiteSpace($Body)) { $Body = 'No metrics found.' } } Catch { $Body = "Error: $($_.Exception.Message)" } $Header = "$Title | every $($RefreshSeconds)s | $([DateTime]::Now.ToString('HH:mm:ss')) | Ctrl+C to exit" $Lines = @($Header, '') + @($Body -split "`r?`n") # Trim to the window so the frame never scrolls, then redraw from the top-left clearing stale text. $Lines = $Lines | Select-Object -First ([Math]::Max([Console]::WindowHeight - 1, 1)) $Frame = ($Lines | ForEach-Object { "$_$Escape[K" }) -join "`n" [Console]::Write("$Escape[H$Frame$Escape[J") $Deadline = [DateTime]::UtcNow.AddSeconds($RefreshSeconds) While([DateTime]::UtcNow -lt $Deadline) { If($PSCmdlet.Stopping) { Return } While($ListenForKeys -and [Console]::KeyAvailable) { $Key = [Console]::ReadKey($True) If(($Key.Key -eq [ConsoleKey]::C) -and ($Key.Modifiers -band [ConsoleModifiers]::Control)) { Return } } Start-Sleep -Milliseconds 50 } } } Finally { # Show the cursor and return to the main screen buffer. [Console]::Write("$Escape[?25h$Escape[?1049l") If($ListenForKeys) { [Console]::TreatControlCAsInput = $PreviousTreatControlCAsInput } } } |