我发现以下脚本可以在日志文件中找到字符串时发送电子邮件
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 $_
}
这很有效,但我想再进一步。当日志文件中抛出异常时,您可以有多行包含匹配的字符串,从而为每行触发多个电子邮件警报,更好的是用一封电子邮件捕获整个错误消息块(或之前的 x 行数)以及之后)
这可以通过 Powershell 实现吗?
提前致谢
唐纳德
我尝试了上面的代码块,当我只想要一封电子邮件时收到了多封电子邮件
示例日志:
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]
解决方案如下:
Start-ThreadJob
cmdlet 实现基于 thread 的并行性(使用 Start-Job
创建的基于子进程的常规后台作业的更快、更轻量的替代方案)。
Install-Module ThreadJob -Scope CurrentUser
。System.Collections.Concurrent.ConcurrentQueue<T>
),其中包含感兴趣的日志消息。
一旦线程作业检测到队列中的消息,它就会额外收集最多 9 条消息,但仅限于 1 秒的窗口内;换句话说:它认为 1 秒间隔内收到的最多 10 条消息属于同一错误,并将它们一起通过电子邮件发送(下面仅模拟发送电子邮件)。
# Create a concurrent (thread-safe) queue.
$msgQueue = [System.Collections.Concurrent.ConcurrentQueue[string]]::new()
# Start a thread job that will monitor the queue and send
# blocks of error lines per email.
$job = Start-ThreadJob {
$msgQueue = $using:msgQueue
$msg = $null
$msgs = [System.Collections.Generic.List[string]] @()
$sw = [System.Diagnostics.Stopwatch]::new()
while ($true) {
# Poll for new queue items every N milliseconds; adjust as needed.
Start-Sleep -Milliseconds 500
# Collect queued messages, up to 10 at a time, if received within
# a 1-second window.
if ($msgQueue.TryDequeue([ref] $msg)) {
$msgs.Add($msg)
# Wait for up to 9 more messages for at most (roughly) 1 second,
# whichever comes first.
$sw.Restart()
while ($msgs.Count -lt 10 -and $sw.Elapsed.TotalSeconds -le 1) {
if ($msgQueue.TryDequeue([ref] $msg)) { $msgs.Add($msg) }
Start-Sleep -Milliseconds 50 # Sleep a little, to avoid a tight loop.
}
# Simulate sending the email with the collected lines.
# Place your Send-MailMessage call here.
# Note:
# [Console]::WriteLine() must be used in order to print to the screen
# from a thread job.
[Console]::WriteLine("--- Emailing the following lines:`n$($msgs -join "`n")")
$msgs.Clear()
}
}
}
# Start the tailing operation (Get-Content -Wait).
# Stopping it requires Ctrl-C.
try {
$logFile = 'C:\temp\server.log'
Get-Content $logFile -Wait -Last 0 |
Where-Object { $_ -match 'ERROR \[STDERR\]' } |
ForEach-Object {
# Enqueue lines of interest, to be processed by the thread job.
$msgQueue.Enqueue($_)
}
}
finally {
# Ctrl-C was pressed: clean up the thread job before exiting.
if ($job) { $job | Remove-Job -Force }
}