diff --git a/examples/Logging.ps1 b/examples/Logging.ps1 index 85be29c4d..9086e83d9 100644 --- a/examples/Logging.ps1 +++ b/examples/Logging.ps1 @@ -84,7 +84,7 @@ Start-PodeServer -browse { } if ( $LoggingType -icontains 'syslog') { - $logging += New-PodeSyslogLoggingMethod -Server 127.0.0.1 -Transport UDP -AsUTC -ISO8601 -FailureAction Report + $logging += New-PodeSyslogLoggingMethod -Server 127.0.0.1 -Transport UDP -AsUTC -ISO8601 -FailureAction Report } if ($logging.Count -eq 0) { @@ -95,14 +95,17 @@ Start-PodeServer -browse { } New-PodeFileLoggingMethod -Name 'error' -MaxDays 4 -Format RFC5424 -ISO8601 | Enable-PodeErrorLogging -Raw -Levels Error - New-PodeFileLoggingMethod -Name 'default' -MaxDays 4 -Format Simple -ISO8601 | Enable-PodeDefaultLogging -Raw + @( + (New-PodeFileLoggingMethod -Name 'default' -MaxDays 4 -Format Simple -ISO8601) + (New-PodeSyslogLoggingMethod -Server 127.0.0.1 -Transport UDP -AsUTC -ISO8601 -SyslogProtocol RFC3164 -FailureAction Report -DefaultTag 'test') + ) | Enable-PodeDefaultLogging -Raw $logging | Add-PodeLogging -Name 'mylog' -Raw:$Raw Write-PodeLog -Name 'mylog' -Message 'just started' -Level 'Info' # GET request for web page on "localhost:8081/" Add-PodeRoute -Method Get -Path '/' -ScriptBlock { Write-PodeLog -Name 'mylog' -Message 'My custom log' -Level 'Info' - Write-PodeLog -Message "This is for the deafult log." + Write-PodeLog -Message 'This is for the deafult log.' Write-PodeViewResponse -Path 'simple' -Data @{ 'numbers' = @(1, 2, 3); } } diff --git a/src/Private/Logging.ps1 b/src/Private/Logging.ps1 index eded1bb69..a0b61acd9 100644 --- a/src/Private/Logging.ps1 +++ b/src/Private/Logging.ps1 @@ -206,7 +206,7 @@ function ConvertTo-PodeSyslogFormat { $message = ($RawItem.Message | Protect-PodeLogItem) } } - +#write-podehost $RawItem -Explode # Map $Level to syslog severity switch ($RawItem.Level) { 'emergency' { $severity = 0; break } @@ -225,6 +225,7 @@ function ConvertTo-PodeSyslogFormat { $facility = 1 # User-level messages $priority = ($facility * 8) + $severity + $processId = $PID # Determine the syslog message format switch ($RFC) { 'RFC3164' { @@ -232,15 +233,14 @@ function ConvertTo-PodeSyslogFormat { $MaxLength = 1024 # Assemble the full syslog formatted message $timestamp = $RawItem.Date.ToString('MMM dd HH:mm:ss') - $fullSyslogMessage = "<$priority>$timestamp $($PodeContext.Server.ComputerName) $Source[$processId]: $message" + $fullSyslogMessage = "<$priority>$timestamp $($PodeContext.Server.ComputerName) $($RawItem.Tag): $message" break } 'RFC5424' { - $processId = $PID $timestamp = $RawItem.Date.ToString('yyyy-MM-ddTHH:mm:ss.ffffffK') # Assemble the full syslog formatted message - $fullSyslogMessage = "<$priority>1 $timestamp $($PodeContext.Server.ComputerName) $Source $processId - - $message" + $fullSyslogMessage = "<$priority>1 $timestamp $($PodeContext.Server.ComputerName) $($RawItem.Tag) $processId - - $message" # Set the max message length per RFC 5424 section 6.1 $MaxLength = 2048 @@ -268,6 +268,7 @@ function ConvertTo-PodeSyslogFormat { if ($MaxLength -gt 0 -and $fullSyslogMessage.Length -gt $MaxLength) { return $fullSyslogMessage.Substring(0, $MaxLength) } + write-podehost $fullSyslogMessage # Return the full syslog formatted message return $fullSyslogMessage } @@ -424,7 +425,7 @@ function Get-PodeLoggingRestfulMethod { return { param($MethodId) - $log = @{} + $log = @{ } while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { Start-Sleep -Milliseconds 100 @@ -435,92 +436,69 @@ function Get-PodeLoggingRestfulMethod { $RawItem = $log.RawItem # Ensure item and rawItem are arrays - if ($Item -isnot [array]) { - $Item = @($Item) - } + $Item = @($Item) + $RawItem = @($RawItem) - if ($RawItem -isnot [array]) { - $RawItem = @($RawItem) - } - - # Determine the transport protocol and send the message + # Determine the platform and send the message switch ($Options.Platform) { 'Splunk' { - # Construct the Splunk API URL $url = "$($Options.BaseUrl)/services/collector" - - # Set the headers for Splunk $headers = @{ 'Authorization' = "Splunk $($Options.Token)" 'Content-Type' = 'application/json' } - $items = @() - for ($i = 0; $i -lt $Item.Length; $i++) { - # Mask values - $message = ($Item[$i] | Protect-PodeLogItem) - if ([string]::IsNullOrWhiteSpace($RawItem[$i].Level)) { - $severity = 'INFO' - } - else { - $severity = $RawItem[$i].Level.ToUpperInvariant() - } - $items += ConvertTo-Json -Compress -InputObject @{ - event = $message - host = $PodeContext.Server.ComputerName - source = $Options.source - time = [math]::Round(($RawItem[$i].Date).ToUniversalTime().Subtract(([datetime]::UnixEpoch)).TotalSeconds) - fields = @{ - severity = $severity + $items = $Item | ForEach-Object { + @{ + event = ($_ | Protect-PodeLogItem) + host = $PodeContext.Server.ComputerName + source = $Options.source + sourcetype = $RawItem.Tag + time = [math]::Round(($RawItem.Date).ToUniversalTime().Subtract(([datetime]::UnixEpoch)).TotalSeconds) + fields = @{ + severity = $RawItem.Level.ToUpperInvariant() } } } + $body = $items | ConvertTo-Json -Compress - $body = $items -join ' ' - - # Send the message to Splunk try { Invoke-RestMethod -Uri $url -Method Post -Headers $headers -Body $body -SkipCertificateCheck:$Options.SkipCertificateCheck } catch { Invoke-PodeHandleFailure -Message "Failed to send log to Splunk: $_" -FailureAction $Options.FailureAction } - break } 'LogInsight' { - # Construct the Log Insight API URL $url = "$($Options.BaseUrl)/api/v1/messages/ingest/$($Options.Id)" - - # Set the headers for Log Insight $headers = @{ 'Content-Type' = 'application/json' } - $messages = @() - for ($i = 0; $i -lt $Item.Length; $i++) { - $messages += @{ - text = ($Item[$i] | Protect-PodeLogItem) - timestamp = [math]::Round(($RawItem[$i].Date).ToUniversalTime().Subtract(([datetime]::UnixEpoch)).TotalSeconds) + + $messages = $Item | ForEach-Object { + @{ + text = ($_ | Protect-PodeLogItem) + timestamp = [math]::Round(($RawItem.Date).ToUniversalTime().Subtract(([datetime]::UnixEpoch)).TotalMilliseconds) + fields = @{ + severity = $RawItem.Level.ToUpperInvariant() + tag = $RawItem.Tag + } } } - # Define the message payload $payload = @{ messages = $messages } - - # Convert payload to JSON $body = $payload | ConvertTo-Json -Compress - # Send the message to Log Insight try { Invoke-RestMethod -Uri $url -Method Post -Body $body -Headers $headers -SkipCertificateCheck:$Options.SkipCertificateCheck } catch { Invoke-PodeHandleFailure -Message "Failed to send log to LogInsight: $_" -FailureAction $Options.FailureAction } - break } } @@ -528,6 +506,7 @@ function Get-PodeLoggingRestfulMethod { } } } + } <# diff --git a/src/Public/Logging.ps1 b/src/Public/Logging.ps1 index 84ecbd46f..21ed3f417 100644 --- a/src/Public/Logging.ps1 +++ b/src/Public/Logging.ps1 @@ -16,6 +16,9 @@ .PARAMETER AsUTC If set, the time will be logged in UTC instead of local time. +.PARAMETER DefaultTag + The tag to use if none is specified on the log entry. Defaults to '-'. + .OUTPUTS Hashtable: Returns a hashtable containing the logging method configuration. @@ -46,7 +49,11 @@ function New-PodeTerminalLoggingMethod { [Parameter()] [switch] - $AsUTC + $AsUTC, + + [Parameter()] + [string] + $DefaultTag = '-' ) # Determine the date format based on parameter set @@ -78,6 +85,7 @@ function New-PodeTerminalLoggingMethod { Arguments = @{ DataFormat = $DataFormat AsUTC = $AsUTC.IsPresent + DefaultTag = $DefaultTag } } } @@ -128,6 +136,9 @@ function New-PodeTerminalLoggingMethod { .PARAMETER AsUTC If set, logs the time in UTC instead of the local time. +.PARAMETER DefaultTag + The tag to use if none is specified on the log entry. Defaults to '-'. + .OUTPUTS Hashtable: Returns a hashtable containing the logging method configuration. @@ -203,7 +214,11 @@ function New-PodeFileLoggingMethod { [Parameter()] [switch] - $AsUTC + $AsUTC, + + [Parameter()] + [string] + $DefaultTag = '-' ) # Determine the date format based on the parameter set @@ -254,6 +269,7 @@ function New-PodeFileLoggingMethod { MaxLength = $MaxLength Source = $Source Separator = $Separator + DefaultTag = $DefaultTag } } } @@ -373,6 +389,7 @@ function New-PodeEventViewerLoggingMethod { FailureAction = $FailureAction DataFormat = $DataFormat AsUTC = $AsUTC.IsPresent + Tag = $Source } } } @@ -420,6 +437,9 @@ function New-PodeEventViewerLoggingMethod { .PARAMETER AsUTC If set, logs the time in UTC instead of local time. +.PARAMETER DefaultTag + The tag to use if none is specified on the log entry. Defaults to '-'. + .EXAMPLE $logMethod = New-PodeSyslogLoggingMethod -Server '192.168.1.100' -Transport 'TCP' -SyslogProtocol 'RFC3164' @@ -488,7 +508,11 @@ function New-PodeSyslogLoggingMethod { [Parameter()] [switch] - $AsUTC + $AsUTC, + + [Parameter()] + [string] + $DefaultTag = '-' ) # Determine the date format based on parameter set @@ -534,6 +558,7 @@ function New-PodeSyslogLoggingMethod { FailureAction = $FailureAction DataFormat = $DataFormat AsUTC = $AsUTC.IsPresent + DefaultTag = $DefaultTag } } } @@ -575,6 +600,9 @@ function New-PodeSyslogLoggingMethod { .PARAMETER AsUTC If set, logs the time in UTC instead of local time. +.PARAMETER DefaultTag + The tag to use if none is specified on the log entry. Defaults to '-'. + .OUTPUTS Hashtable: Returns a hashtable containing the RESTful logging method configuration. @@ -632,7 +660,11 @@ function New-PodeRestfulLoggingMethod { [Parameter()] [switch] - $AsUTC + $AsUTC, + + [Parameter()] + [string] + $DefaultTag = '-' ) # Determine the date format based on parameter set @@ -669,6 +701,7 @@ function New-PodeRestfulLoggingMethod { FailureAction = $FailureAction DataFormat = $DataFormat AsUTC = $AsUTC.IsPresent + DefaultTag = $DefaultTag } } } @@ -1764,9 +1797,12 @@ function Write-PodeLog { [string] $Message, + [Parameter(ParameterSetName = 'ErrorRecord')] + [Parameter(ParameterSetName = 'Message')] + [Parameter(ParameterSetName = 'Exception')] [Parameter()] [string] - $Tag = '-', + $Tag, [Parameter(ParameterSetName = 'InputObject')] [Parameter(ParameterSetName = 'Message')] @@ -1793,8 +1829,9 @@ function Write-PodeLog { # Define the log item based on the selected parameter set. switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 'inputobject' { - if (!$Level) { $Level = 'Informational' } - if ( @(Get-PodeLoggingLevel -Name $Name) -inotcontains $Level) { return } + if (!$Level) { $Level = 'Informational' } # Default to Informational. + if ( @(Get-PodeLoggingLevel -Name $Name) -inotcontains $Level) { return } # If the level is not configured, use the + $logItem = @{ Name = $Name Item = $InputObject @@ -1803,8 +1840,10 @@ function Write-PodeLog { break } 'message' { - if (!$Level) { $Level = 'Informational' } - if ( @(Get-PodeLoggingLevel -Name $Name) -inotcontains $Level) { return } + if (!$Level) { $Level = 'Informational' } # Default to Informational. + if ( @(Get-PodeLoggingLevel -Name $Name) -inotcontains $Level) { return } # If the log level is not configured, return. + if ([string]::IsNullOrEmpty($Tag)) { $Tag = $PodeContext.Server.Logging.Type[$Name].Method.Arguments.DefaultTag } # If the tag is not specified, use the default tag for the log method. + $logItem = @{ Name = $Name Item = @{ @@ -1817,8 +1856,10 @@ function Write-PodeLog { break } 'exception' { - if (!$Level) { $Level = 'Error' } - if ( @(Get-PodeLoggingLevel -Name $Name) -inotcontains $Level) { return } + if (!$Level) { $Level = 'Error' } # Default to Error. + if ( @(Get-PodeLoggingLevel -Name $Name) -inotcontains $Level) { return } # If the level is not supported, return. + if ([string]::IsNullOrEmpty($Tag)) { $Tag = $PodeContext.Server.Logging.Type[$Name].Method.Arguments.DefaultTag } # If the tag is not specified, use the default tag for the log method. + $logItem = @{ Name = $Name Item = @{ @@ -1830,8 +1871,10 @@ function Write-PodeLog { break } 'errorrecord' { - if (!$Level) { $Level = 'Error' } - if ( @(Get-PodeLoggingLevel -Name $Name) -inotcontains $Level) { return } + if (!$Level) { $Level = 'Error' } # Default to Error. + if ( @(Get-PodeLoggingLevel -Name $Name) -inotcontains $Level) { return } # If the level is not supported, return. + if ([string]::IsNullOrEmpty($Tag)) { $Tag = $PodeContext.Server.Logging.Type[$Name].Method.Arguments.DefaultTag } # If the tag is not specified, use the default tag for the log method. + $logItem = @{ Name = $Name Item = @{