【问题标题】:Real Time monitoring for errors in log files in windows实时监控windows日志文件中的错误
【发布时间】:2021-05-09 21:00:48
【问题描述】:

我的服务器上部署了多个 Windows 服务。我想实现一个 PowerShell 脚本,它可以对这些服务的日志进行实时监控。它必须在日志文件中查找关键字(例如错误、异常),一旦出现任何错误,脚本应该向预先配置的电子邮件地址发送通知。 我在网上进行了基本搜索,可以找到一些可以做到这一点的免费软件应用程序,但我并不热衷于在服务器上安装这些应用程序。如果这可以通过基本的 PowerShell 脚本或批处理脚本来完成,并且可以在后台运行,那就太好了。

我找到了可以实时查看文件的 Get-Content 和 Type -wait 命令

Get-Content error.log -wait | where { $_ -match "ERROR" }

非常感谢您在电子邮件通知部分提供的任何帮助,如果您可以添加一些可能有帮助的网络链接。

有点复杂的是日志文件不会是固定的,每天都会创建一个新的日志文件,脚本应该根据文件名或创建日期等自动识别最新的文件。

文件名格式为 8_05_2021.txt、9_05_2021.txt、10_05_2021.txt

【问题讨论】:

  • 这个脚本是计划任务吗?如果是这样,该任务的触发器是什么?它会 24x7 全天候运行,还是您打算在每天结束后破坏脚本?
  • @SantiagoSquarzon,这可能是一个计划任务,或者应该持续运行,因为文件监控需要实时。
  • 所以日志是每天在包含特定关键字的目录中的新日志?还是系统、应用程序等 Windows 日志?
  • @AbrahamZinala 这些不是 Windows 事件日志,您是对的,日志文件位于一个目录下,并且每天都会创建一个新文件。我们需要在日志文件中查找错误。
  • 为工作使用正确的工具。您为什么要尝试编写此脚本(这是一个无限循环(只是一个坏主意)或定时任务要好一点)而不是使用日志收集解决方案?为此使用企业服务。您可以使用Windows FSRM (File Server Resource Manager) 来监视这些文件并关闭其中的数据。 FSRM Configure E-Mail Notifications

标签: windows powershell monitoring


【解决方案1】:

如果我的逻辑是正确的,我认为这应该可行,该脚本将无限期运行。

对于在 PowerShell 中发送邮件,我知道有两种选择,一种是使用为此设计的 cmdlet:Send-MailMessage

但是,请务必注意这一点:

警告
Send-MailMessage cmdlet 已过时。此 cmdlet 不保证与 SMTP 服务器的安全连接。虽然 PowerShell 中没有立即可用的替代品,但我们建议您不要使用 Send-MailMessage。有关详细信息,请参阅平台兼容性说明 DE0005。

您可以使用Net.Mail.MailMessage 找到第二个选项here

现在对于脚本的代码,您可以使用以下内容:

# Define the full path of your logs folder
$logsFolder = 'fullPath\to\logsFolder'

# Function for monitoring and retrieving the newest log file Full Path
function monitorPath($LogPath){
    (Get-ChildItem "$LogPath\*.txt" |
    Sort-Object -Descending CreationTime |
    Select-Object -First 1).FullName
}

# Get the newest log file
$logFilePath = monitorPath -LogPath $logsFolder

while($true)
{
    # If we don't have today's date stored
    # or the update trigger is True
    if($updateDate -or -not $today)
    {
        $today = [datetime]::Today
        $updateDate = $false
    }
    
    if($today -lt [datetime]::Today)
    {
        # Trigger our previous condition
        $updateDate = $true

        # Get the new log file for this day
        $logFilePath = monitorPath -LogPath $logsFolder
    }

    if((Get-Content $logFilePath -Raw) -match 'Error')
    {
        # Send mail message goes here
    }

    Start-Sleep -Seconds 60
}

请务必注意,如果日志文件中有错误,这将每分钟向您的收件箱发送垃圾邮件,因此在此块中添加新条件可能是个好主意:

if((Get-Content $logFilePath -Raw) -match 'Error')
{ .... }

例如这样的:

if((Get-Content $logFilePath -Raw) -match 'Error' -and -not $emailSentThisDay)
{
    # Send mail message goes here

    # Here you set this bool to True so you don't get spammed :D
    $emailSentThisDay = $true
}

如果这是您将考虑的事情,那么您将需要每天重置 $emailSentThisDay 布尔值,所以:

if($today -lt [datetime]::Today)
{
    # Trigger our previous condition
    $updateDate = $true

    # Reset the antispam bool if this is a new day
    $emailSentThisDay = $false
    
    # Get the new log file for this day
    $logFilePath = monitorPath -LogPath $logsFolder
}

【讨论】:

【解决方案2】:

注意:下面的解决方案仅实时监控日志文件添加继续,它不考虑旧日志文件,也不会持续跟踪日志文件到哪一行已经处理过——这样的逻辑需要(大量)额外的努力。

您可以使用以下方法:

  • 使用background jobs(使用Start-Job 创建)或最好使用thread [background] jobs(使用Start-ThreadJob 创建)来监控对给定日志文件的添加。

  • 在前台,周期性地运行一个循环:

    • 轮询作业以查找感兴趣的新日志文件内容并发送电子邮件(如果找到)。
    • 检查是否存在日志文件,如果找到,则终止当前作业并为新日志文件启动新作业。

注意:

  • 您可以使用Send-MailMessage 发送电子邮件,但请注意,此 cmdlet 被视为已过时,因为它“不保证与 SMTP 服务器的安全连接”。也就是说,如果这不是您的问题,它可以工作,并且鉴于 PowerShell 对向后兼容性的承诺,该 cmdlet 不太可能被删除

  • 代码运行无限期;当以交互方式运行时,您可以使用 Ctrl-C 终止它,但在自动调用场景(例如计划任务)中,您必须终止该任务。

$logFileDir = '.'
$job = $null
$currLogFile = $null

while ($true)
{

  # Check for new content of interest from the background job.
  if ($job -and ($result = Receive-Job $job)) {
    # Send an email here, e.g.:
    # Send-MailMessage -SmtpServer exchange.example.com -From alerts@example.com -To jdoe@example.com -Subject 'Error' -Body $result
  }

  # See if a new log file has appeared.
  # For simplicity, go by creation date.
  # If a new file only appears once a day, you could keep track
  # of the current calendar date and only look when it changes.
  $newLogFile = (Get-ChildItem -File "$logFile/*_*_*.txt" | 
                  Sort-Object -Descending CreationTime | 
                    Select-Object -First 1).FullName
  
  if ($newLogFile -ne $currLogFile) {

    # If there's a current job for the previous log file, terminate it now.
    if ($job) { Remove-Job $job -Force }

    # Create a job for the new log file.
    $currLogFile = $newLogFile
    $job = Start-Job {
       # Wait indefinitely for content to be added to the file,
       # and output lines matching the string of interest.
       Get-Content -LiteralPath $using:currLogFile -Wait |
         Where-Object { $_ -match "ERROR" }
    }

  }

  # Sleep a little.
  Start-Sleep -Seconds 1
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 2010-09-11
    • 1970-01-01
    相关资源
    最近更新 更多