EventMonitor/EventDispatch.ps1
|
# ── Logging & Event Dispatch ────────────────────────────────────────────────── # Centralized logging helper and the function that enriches Windows events # with full metadata before forwarding them to Application Insights. <# .SYNOPSIS Writes a timestamped, leveled entry to the local operational log file. .DESCRIPTION All module components use this single function for local file logging. Respects the configured log level — messages below the threshold are silently dropped. Log levels (in order): Debug < Info < Warning < Error .PARAMETER Message The log message text. .PARAMETER Level Debug, Info, Warning, or Error. Defaults to Info. #> function Write-EMLog { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Message, [ValidateSet('Debug', 'Info', 'Warning', 'Error')] [string]$Level = 'Info' ) # Level filtering — skip messages below the configured threshold $levelOrder = @{ 'Debug' = 0; 'Info' = 1; 'Warning' = 2; 'Error' = 3 } $configLevel = if ($script:MonitoringConfig) { $script:MonitoringConfig.LogLevel } else { 'Info' } if ($levelOrder[$Level] -lt $levelOrder[$configLevel]) { # Still mirror to verbose for interactive debugging even if not logged Write-Verbose "$Level :: $Message" return } $timestamp = Get-Date -Format 'yyyy-MM-ddTHH:mm:ss' $entry = "$timestamp :: [$Level] $Message" try { # Daily log file path (updates if date rolls over during long-running service) $script:LogFilePath = Join-Path $script:LogDir "Operational-$(Get-Date -Format 'yyyy-MM-dd').log" Add-Content -Path $script:LogFilePath -Value $entry -ErrorAction Stop } catch { Write-Warning "Failed to write to log: $entry" } # Mirror to verbose stream for interactive debugging Write-Verbose $entry } <# .SYNOPSIS Enriches a Windows event with full metadata and dispatches it to all telemetry sinks. .DESCRIPTION Merges caller-supplied properties with all available fields from the raw EventRecord (Id, Message, TimeCreated, MachineName, all indexed properties, etc.) and dispatches the combined payload via TrackEvent. .PARAMETER eventName Name for the telemetry event. .PARAMETER Properties Caller-supplied key-value properties (SessionId, EventType, UserName, etc.). .PARAMETER sendEvent The raw Windows EventRecord to extract metadata from. #> function Send-LogAnalyticsConnectEvents { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$eventName, [Parameter(Mandatory)] [System.Collections.Generic.Dictionary[string, string]]$Properties, [System.Diagnostics.Eventing.Reader.EventRecord]$sendEvent ) try { # Build a merged property dictionary: caller props + event metadata $allProps = [System.Collections.Generic.Dictionary[string, string]]::new() foreach ($key in $Properties.Keys) { $allProps[$key] = $Properties[$key] } if ($null -ne $sendEvent) { $allProps['EventId'] = "$($sendEvent.Id)" $allProps['Message'] = "$($sendEvent.Message)" $allProps['TimeCreated'] = "$($sendEvent.TimeCreated)" $allProps['Level'] = "$($sendEvent.Level)" $allProps['Keywords'] = "$($sendEvent.Keywords)" $allProps['RecordId'] = "$($sendEvent.RecordId)" $allProps['ProviderId'] = "$($sendEvent.ProviderId)" $allProps['ProviderName'] = "$($sendEvent.ProviderName)" $allProps['ThreadId'] = "$($sendEvent.ThreadId)" $allProps['MachineName'] = "$($sendEvent.MachineName)" $allProps['UserId'] = "$($sendEvent.UserId)" $allProps['ActivityId'] = "$($sendEvent.ActivityId)" $allProps['RelatedActivityId'] = "$($sendEvent.RelatedActivityId)" $allProps['ContainerLog'] = "$($sendEvent.ContainerLog)" $allProps['MatchedQueryIds'] = "$($sendEvent.MatchedQueryIds)" $allProps['LevelDisplayName'] = "$($sendEvent.LevelDisplayName)" $allProps['TaskDisplayName'] = "$($sendEvent.TaskDisplayName)" $idx = 0 foreach ($p in $sendEvent.Properties) { $idx++ $allProps["Property[$idx]"] = "$($p.Value)" } } TrackEvent -Name $eventName -Properties $allProps } catch { Write-EMLog -Message "Send-LogAnalyticsConnectEvents failed for '$eventName': $($_.Exception.Message)" -Level Error $errorProps = [System.Collections.Generic.Dictionary[string, string]]::new() $errorProps['Function'] = 'Send-LogAnalyticsConnectEvents' $errorProps['EventName'] = $eventName TrackException -ErrorRecord $_ -Properties $errorProps } } |