带有 Powershell 和电子邮件的尾部日志文件,但仅在第一次出现时才出现,直到下一次

问题描述 投票:0回答:1

我发现以下脚本可以在日志文件中找到字符串时发送电子邮件

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]
powershell email logging alert tail
1个回答
0
投票

解决方案如下:

  • 使用

    Start-ThreadJob
    cmdlet 实现基于 thread 的并行性(使用
    Start-Job
    创建的基于子进程的常规后台作业的更快、更轻量的替代方案)。

    • 它配备了 PowerShell (Core) 7+,并且可以在 Windows PowerShell 中按需安装,例如
      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 }
}

© www.soinside.com 2019 - 2024. All rights reserved.