Public/Logs/Watch-JIMLog.ps1
|
# Copyright (c) Tetron Limited. All rights reserved. # Licensed under the Tetron Commercial License. See LICENSE file in the project root. function Watch-JIMLog { <# .SYNOPSIS Streams JIM service log entries to the console. .DESCRIPTION Continuously polls JIM's Logs API and displays new log entries as they arrive, colour-coded by level (red for Error/Fatal, yellow for Warning, dark grey for Debug/Verbose). The first poll establishes a baseline; subsequent polls display only entries newer than the last one seen. Runs until interrupted with Ctrl+C (or until -MaxPolls cycles have completed). Transient API failures are reported as warnings and polling continues. Output is formatted for the console. For structured log entry objects suitable for the pipeline, use Get-JIMLogEntry instead. .PARAMETER Service Filter by service name (web, worker, scheduler). Omit for all services. .PARAMETER Level Specific log levels to include (Verbose, Debug, Information, Warning, Error, Fatal). Omit for all levels. .PARAMETER Search Text to search for in the log message (case-insensitive). .PARAMETER IntervalSeconds Number of seconds to wait between polls (1-300). Defaults to 2. .PARAMETER MaxPolls Maximum number of poll cycles to run before stopping. Omit to run until interrupted with Ctrl+C. Useful for bounded watches in scripts. .OUTPUTS None. Log entries are written to the console as formatted, colour-coded lines. .EXAMPLE Watch-JIMLog Streams log entries from all services until interrupted with Ctrl+C. .EXAMPLE Watch-JIMLog -Service worker -Level Error, Fatal Streams only Error and Fatal entries from the worker service. .EXAMPLE Watch-JIMLog -IntervalSeconds 5 Streams log entries, polling the API every 5 seconds. .LINK Get-JIMLogEntry .LINK Get-JIMLogFile #> [CmdletBinding()] [OutputType([void])] param( [string]$Service, [string[]]$Level, [string]$Search, [ValidateRange(1, 300)] [int]$IntervalSeconds = 2, [ValidateRange(1, [int]::MaxValue)] [int]$MaxPolls ) process { # Check connection first if (-not $script:JIMConnection) { Write-Error "You are not connected to JIM. Run Connect-JIM -Url <your JIM URL> to authenticate, then try again." return } # Build the query string once; the filters do not change between polls. # Entries come back newest first, so a fixed limit gives us the most recent # window on every poll. $queryParams = @( "limit=200", "offset=0" ) if ($Service) { $queryParams += "service=$([System.Uri]::EscapeDataString($Service))" } if ($Search) { $queryParams += "search=$([System.Uri]::EscapeDataString($Search))" } if ($Level) { foreach ($l in $Level) { $queryParams += "levels=$([System.Uri]::EscapeDataString($l))" } } $endpoint = "/api/v1/logs?" + ($queryParams -join '&') Write-Host "Watching JIM logs (polling every $IntervalSeconds seconds). Press Ctrl+C to stop." -ForegroundColor Cyan $lastSeen = [datetime]::MinValue $baselineEstablished = $false $pollIndex = 0 while ($true) { $pollIndex++ try { $entries = @(Invoke-JIMApi -Endpoint $endpoint) if (-not $baselineEstablished) { # First successful poll: record the newest timestamp without # displaying anything, so only entries logged from now on appear. foreach ($entry in $entries) { if ($entry.Timestamp -gt $lastSeen) { $lastSeen = $entry.Timestamp } } $baselineEstablished = $true } else { $newEntries = @($entries | Where-Object { $_.Timestamp -gt $lastSeen } | Sort-Object Timestamp) foreach ($entry in $newEntries) { $levelLabel = if ($entry.LevelShort) { $entry.LevelShort } else { $entry.Level } $line = "[{0:yyyy-MM-dd HH:mm:ss}] [{1}] [{2}] {3}" -f $entry.Timestamp, $levelLabel, $entry.Service, $entry.Message $colour = Get-JIMLogLevelColour -Level $entry.Level if ($colour) { Write-Host $line -ForegroundColor $colour } else { Write-Host $line } if ($entry.Exception) { Write-Host $entry.Exception -ForegroundColor DarkGray } if ($entry.Timestamp -gt $lastSeen) { $lastSeen = $entry.Timestamp } } } } catch { # Transient API failures must not end the watch; warn and keep polling. Write-Warning "Failed to retrieve log entries: $($_.Exception.Message). Retrying in $IntervalSeconds seconds." } if ($MaxPolls -gt 0 -and $pollIndex -ge $MaxPolls) { break } Start-Sleep -Seconds $IntervalSeconds } } } |