PowerShell Tiny Project #12 - Real-time Tracking of Application Event Logs
In any debugging scenarios, we're drawn into reviewing the logs and if the application was developed with decent error handling and logging mechanism we have a good chance of finding our first clue. Not all the logs are clear and I have seen many .NET and Java-based applications giving you cryptic error stacks. Some applications allow you to increase the level of verbosity in exchange for lower performance. This is a good tradeoff to make when you don't have much to work with. If you're working with an application directory where all the logs are kept, searching is not that difficult:
Here you can match patterns with select-string
cmdlet and specify the type of files you're looking for with your get-childitem
cmdlet. The same thing could be achieved using Notepad++. Going to search and selecting find in files gives you pretty much the same interface.
This approach is effective not only for reviewing logs for errors but also for locating specific settings in configuration files. I've encountered situations where I needed to find a specific application setting and wasn't certain of its location. With this method, I promptly pinpointed its position. Some applications take advantage of Windows Application Event Log. Let's see the basic interactions before we get to our tiny project.
Windows Application Event Log is a centralized system log meant to store messages from all applications running on a system that opt to write there. I know that we all tend to look at application-specific logs, but you'd be surprised how much information, especially for system-wide issues is stored there. Since it's a standardized system, many third-party tools and systems can integrate with Windows Event Logs for monitoring and alerting purposes. Let's see how we can interact with it for historical and real-time events.
PowerShell can be used to interact with Windows event logs, both for reading from and writing to them. PowerShell provides a set of cmdlets that make it relatively straightforward to manage and query event logs.
Here are some of the common tasks you might want to perform with Windows event logs using PowerShell:
View All Event Logs:
Get-EventLog -List
Read Entries from a Specific Event Log: For example, to read the latest 20 entries from the "Application" log:
Get-EventLog -LogName "Application" -Newest 20
Filter Entries Based on Specific Criteria: For instance, to get all "Error" type events from the "System" log:
Get-EventLog -LogName "System" | Where-Object {$_.EntryType -eq "Error"}
Write to an Event Log: This example writes an informational entry to the "Application" log:
Write-EventLog -LogName "Application" -Source "YourAppName" -EntryType Information -EventId 1000 -Message "Your custom message here."
Armed with this information, let's work on our tiny project. In earlier tiny projects we learned that we can use Register-ObjectEvent to register event subscribers to listen for a specific event on a given object. We can take the same approach to create an object for eventlogs and set an event listener that listens for "EntryWritten" events.
$eventLog = New-Object System.Diagnostics.EventLog("Application")
Register-ObjectEvent $eventLog "EntryWritten" -Action {
Write-Host "New log entry: $($event.SourceEventArgs.Entry.Message)"
}
$eventLog.EnableRaisingEvents = $true
# To keep the script running
while ($true) {
Start-Sleep -Seconds 10
}
Please note that $eventLog.EnbaleRaisingEvents
has to be set to true which in turn enables the raising of events for our object. The little gotcha here is that if this isn't set to true the script won't react to new entries even though the event listener is registered.
We can test this approach either by waiting for new entries to be generated in the Application logs or using PowerShell to create an entry:
# Define the parameters for the event log entry
$LogName = "Application"
$Source = "CustomScript"
$EventID = 1001
$EntryType = "Information"
$Message = "This is a test message from CustomScript."
# Check if the event log source already exists. If not, create it.
if (-not (Get-EventLog -LogName $LogName -ErrorAction SilentlyContinue | Where-Object { $_.Source -eq $Source })) {
New-EventLog -LogName $LogName -Source $Source
}
# Write the event log entry
Write-EventLog -LogName $LogName -Source $Source -EventId $EventID -EntryType $EntryType -Message $Message
If the event log source doesn't exist you'll get an error message. So it's better to check for its existence and if it doesn't exist then create it.
There you have it, as you can see it is very easy to build an API around the event logs. Instead of writing the new entries to the console, you can append them to a file and turn that into a stream.
Add-Content -Path $filePath -Value "New log entry: $($event.SourceEventArgs.Entry.Message)"