psmcp.logger.ps1
|
<#
.SYNOPSIS Writes a log entry to a file or console with rotation and structured output. .DESCRIPTION Supports file and console logging modes. Handles log rotation by file size and age. Outputs structured JSON logs. .PARAMETER LogEntry Hashtable containing log details. Mandatory. .PARAMETER LogFilePath Optional path to the log file. If not specified, uses environment variable or default path. .PARAMETER Mode Logging mode: 'File' (default) or 'Console'. .EXAMPLE psmcp.writeLog -LogEntry @{ what = 'Test'; message = 'Hello' } -Mode 'Console' #> function psmcp.writeLog { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] param( [Parameter(Mandatory)] [hashtable] $LogEntry, [Parameter(Mandatory = $false)] [string] $LogFilePath, [ValidateSet('File', 'Console')] [string] $Mode = 'File' ) $LogEntry = $LogEntry ?? @{} $baseLog = [ordered]@{ WHEN = (Get-Date).ToUniversalTime().ToString('o') WHAT = $LogEntry['what'] ?? 'MCP_DEBUG_LOG_ENTRY' PSCallStack = Get-PSCallStack | Select-Object -Skip 1 -ExpandProperty Command modulePath = $MyInvocation.MyCommand.Module.Path log = $LogEntry } $PWSH_MCP_SERVER_LOG_MAX_SIZE_KB = 10 $PWSH_MCP_SERVER_LOG_ROTATION_MINUTES = 15 switch ($Mode) { 'Console' { $baseLog = [ordered]@{ jsonrpc = '2.0'; method = 'notifications'; params = $baseLog } Write-Output ($baseLog | ConvertTo-Json -Depth 10 -Compress) } 'File' { $effectivePath = $LogFilePath ?? $env:PWSH_MCP_SERVER_LOG_FILE_PATH ?? [IO.Path]::Combine(($HOME ?? [Environment]::GetFolderPath('UserProfile')), '.cache', 'mcp', 'pwsh_mcp_server.log') if ($PSCmdlet.ShouldProcess($effectivePath, 'Write log entry')) { $dir = [IO.Path]::GetDirectoryName($effectivePath) if ($dir -and -not (Test-Path -LiteralPath $dir)) { New-Item -ItemType Directory -Path $dir -Force -ea SilentlyContinue | Out-Null } if (Test-Path $effectivePath) { $fi = Get-Item $effectivePath $aged = (New-TimeSpan -Start $fi.LastWriteTime -End (Get-Date)).TotalMinutes -gt $PWSH_MCP_SERVER_LOG_ROTATION_MINUTES $oversized = $fi.Length -gt ($PWSH_MCP_SERVER_LOG_MAX_SIZE_KB * 1KB) if ($aged -or $oversized) { Rename-Item $effectivePath -NewName "$($fi.BaseName).$(Get-Date -Format 'yyyyMMddHHmmssfff').log" -ea SilentlyContinue } } Add-Content -Path $effectivePath -Value ($baseLog | ConvertTo-Json -Depth 10 -Compress) -Encoding UTF8 -ea SilentlyContinue } } } } |