Public/Get-KubeLog.ps1
|
Function Get-KubeLog { <# .SYNOPSIS Retrieves Kubernetes pod logs for a specific pod or a set of pods selected by label, optionally filtering by container, namespace, previous container instance, time window, or tail length. This command is the log retrieval entry point for KubePS and supports both one-off log reads and live follow mode, making it suitable for troubleshooting running applications and checking recent failures in a namespace or pod set. .EXAMPLE Get-KubeLog -Pod api -Namespace default # Reads logs from the api pod in the default namespace and writes the full log output. .EXAMPLE Get-KubeLog -Label app=frontend -Namespace default -TailLines 100 # Returns the last 100 log lines from pods that match the app=frontend label selector. .EXAMPLE Get-KubeLog -Pod api -Namespace default -Follow -Since '30m' # Streams new log output continuously from the past 30 minutes until the stream is stopped. #> [CmdletBinding(DefaultParameterSetName = 'Default')] param( [Parameter(Mandatory=$False, ParameterSetName='Pod', Position=1, HelpMessage='The pod to retrieve logs for.')] [string]$Pod, [Parameter(Mandatory=$False, ParameterSetName='Label', Position=1, HelpMessage='The label to filter pods by.')] [string]$Label, [Parameter(Mandatory=$False, Position=1, HelpMessage='The container to retrieve logs for.')] [string]$Container, [Parameter(Mandatory=$False, HelpMessage='Retrieve logs from the previous instance of the container.')] [switch]$Previous, [Parameter(Mandatory=$False, HelpMessage='The time duration to retrieve logs for. Example: 1h, 30m, 15s.')] [ValidatePattern('^\d+[smhd]$')] [String]$Since, [Parameter(Mandatory=$False, HelpMessage='The number of lines to retrieve from the end of the log.')] [int]$TailLines = $null, [Parameter(Mandatory=$False, HelpMessage='Output the logs with timestamps.')] [switch]$Timestamps, [Parameter(Mandatory=$False, HelpMessage='Follow the log output.')] [switch]$Follow ) DynamicParam { $DynamicParameterDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() $NewDynamicParams = @{ DynamicParameterDictionary = $DynamicParameterDictionary } $Namespaces = Get-KubeNamespace $ParamList = @( @{ ParameterName = 'Namespace' ParameterType = ([string]) DefaultValue = $Script:SelectedNamespace Mandatory = $False ValidateSet = [array]$Namespaces.Name HelpMessage = 'The namespace to set as the context for retrieving pod logs.' Position = 3 } ) ForEach($Param in $ParamList) { Add-DynamicParameter @NewDynamicParams @Param } Return $DynamicParameterDictionary } Begin { $SinceSeconds = $null If([string]::IsNullOrEmpty($Since) -eq $False) { $SinceSeconds = ConvertTo-Seconds -Duration $Since } } Process { $Namespace = $DynamicParameterDictionary['Namespace'].Value $GetPodParams = @{ FullOutput = $True } Switch($PSCmdlet.ParameterSetName) { 'Pod' { If([string]::IsNullOrWhiteSpace($Namespace)) { Write-Error 'Specify -Namespace or use Set-SelectedNamespace.' -Category InvalidArgument Return } $GetPodParams['Pod'] = $Pod $GetPodParams['Namespace'] = $Namespace } 'Label' { If([string]::IsNullOrWhiteSpace($Namespace) -eq $False) { $GetPodParams['Namespace'] = $Namespace } $GetPodParams['Label'] = $Label } } Try { $PodItems = @(Get-KubePod @GetPodParams) } Catch { Write-Error "Failed to retrieve pods: $($_.Exception.Message)" -Category InvalidOperation Return } If($PodItems.Count -eq 0) { Write-Error 'No pods found matching the specified criteria.' -Category ObjectNotFound Return } ForEach($PodItem in $PodItems) { $PodName = $PodItem.Metadata.Name $PodNamespace = $PodItem.Metadata.NamespaceProperty If([string]::IsNullOrWhiteSpace($PodNamespace)) { $PodNamespace = $Namespace } $Containers = @($PodItem.Spec.Containers | ForEach-Object Name) If([String]::IsNullOrEmpty($Container) -eq $False) { If(-not $Containers.Contains($Container)) { Write-Error "The specified container '$Container' does not exist in pod '$PodName'." -Category InvalidArgument Continue } $Containers = @($Container) } ForEach($ContainerName in $Containers) { $TaillinesParameter = If($TailLines -eq 0) { [System.Type]::Missing } Else { [int]$TailLines } $LogStreamArguments = [object[]]@( $Script:KubePSDirectClient.CoreV1, # Client [string]$PodName, # name [string]$PodNamespace, # namespace [string]$ContainerName, # container [bool]$Follow, # follow $null, # insecureSkipTLSVerifyBackend $null, # limitBytes $null, # pretty [bool]$Previous, # previous $SinceSeconds, # sinceSeconds [System.Type]::Missing, # stream $TaillinesParameter, # tailLines [bool]$Timestamps, # timestamps [System.Threading.CancellationToken]::None # cancellationToken ) $Method = [k8s.CoreV1OperationsExtensions].GetMethod('ReadNamespacedPodLogAsync') $LogStream = $Method.Invoke($null, $LogStreamArguments).GetAwaiter().GetResult() If($null -eq $LogStream) { Write-Verbose "No log stream available for pod '$PodName' in namespace '$PodNamespace'" Continue } $Reader = [System.IO.StreamReader]::new($LogStream) Try { If($Follow) { Start-LogStreamer -LogStream $Reader } Else { $Reader.ReadToEnd() } } Finally { $Reader.Dispose() $LogStream.Dispose() } } } } } |