I've found the following script to send an email when a string is found in a log file
Get-Content C:\temp\server.log -Wait -Last 0 |
Where-Object { $_ -match "ERROR \[STDERR\]" } |
ForEach-Object {
Send-MailMessage -SmtpServer x.x.x.x -From ALERT@com -To alert.com -Subject 'Error' -Body $_
}
This works well but I'd like to take it a couple of steps further. When exceptions are thrown in the log file you can have multiple lines with the matched string thus triggering multiple email alerts for each line, what would be better is a single email to catch the whole block of the error message ( or x number of lines before and after)
Is this possible with Powershell?
Thanks in advance
Donald
I tried the block of code above and got multiple emails when I only want a single email
Sample log:
09:14:01,407 ERROR [org.apache.struts.action.RequestProcessor]
09:21:34,649 ERROR [stderr] (default task- 554java.io.IOException:
09:21:34,650 ERROR [stderr] (default task-554) at java.base/
09:21:34,650 ERROR [stderr] (default task-554) at java.base/
12:18:53,286 ERROR [org.apache.struts.action.RequestProcessor] (default task- 949) Invalid path
12:24:06,441 ERROR [org.apache.struts.action.RequestProcessor] (default task- 957) Invalid path
14:23:57,661 ERROR [stderr] (default task-1114at [email protected]//org.
[email protected].
14:23:57,661 ERROR [stderr] (default task-1114) at [email protected]
The following solution:
Uses the
Start-ThreadJobcmdlet for thread-based parallelism (a faster and lighter-weight alternative to the child-process-based regular background jobs created withStart-Job).Install-Module ThreadJob -Scope CurrentUser.The thread job the solution creates monitors a concurrent, i.e. thread-safe queue (
System.Collections.Concurrent.ConcurrentQueue<T>), filled by the main thread with the log messages of interest.Once the thread job detects a message in the queue, it collects up to 9 additional ones, but only within a 1-second window; in other words: it considers up to 10 messages received within a 1-second interval to belong to the same error, and emails them together (sending of the email is only simulated below).
Note: A bug in
Get-Contentin PowerShell 7.4.0 and 7.4.1 prevents-Tail 0from working in combination with-Wait(no waiting occurs). This is expected to get fixed in 7.4.2 - see GitHub PR #20734. To work around the bug, the code below uses-Tail 1Self-contained example with debugging:
Note:
The following requires PowerShell (Core) 7+, because Windows PowerShell seemingly doesn't support debugging thread jobs (those started with
Start-ThreadJobas opposed to (child process-based) background jobs started withStart-Job) viaDebug-JobDue to a bug in version 2.3.4 of the
PSReadLinemodule (the one that ships with PowerShell 7.4.1), it must be (temporarily) unloaded before running debugging withDebug-Job, which the code automatically does - see GitHub issue #3954.To ensure that the debugger reliably breaks into the thread job every time
Debug-Jobis called, a dummySet-PSBreakpointcall is used; as of PowerShell 7.4.1, placing aWait-Debuggercall inside a thread job seemingly cause a hang whenDebug-Jobis called; see the source-code comments for details, and GitHub issue #21257.Instructions:
For simplicity, a
sample_log.txtfile in the current directory is created and tailed, which is automatically removed on exit.When you run the script, it prints instructions on how to append lines of interest to
log.txton demand, from a separate session, so as to trigger processing (be sure to run the other session in the same directory or targetlog.txtby its full path).Once the debugger is entered and you're done debugging, use
dto continue execution, which detaches the debugger and resumes foreground execution; it is re-entered every time new lines of interest are received.However, note that debugging can interfere with the logic of the 1-second time window for collecting messages, so that a single block of related lines can result in multiple debugger invocations and multiple simulated emails.
For instructions on how to use the debugger, see the conceptual about_Debuggers help topic.
Use Ctrl-C to terminate execution overall.