PowerShell如何实现日志超5分钟无活动的检测触发功能
PowerShell 日志5分钟无活动检测实现方案
核心逻辑是放弃原代码中Get-Content -Wait的阻塞式监听,改用非阻塞的轮询机制,独立维护最后活动时间戳,在不影响原有日志匹配处理逻辑的前提下实现超时检测。
实现要点
- 初始化时记录最后一次日志活动时间,设置5分钟超时阈值,新增防重复通知标记避免同一段无活动周期内重复触发通知
- 用文件流指针记录读取位置,每次轮询只读取上次读取后新增的日志内容,和原代码
-Tail 1 -Wait的行为保持一致,不会重复处理历史日志 - 每次读取到匹配
myapp规则的新日志行时,立刻重置最后活动时间、清除通知触发标记,同时执行原有的行处理逻辑 - 每轮轮询计算当前时间和最后活动时间的差值,达到5分钟阈值且未发过通知时,直接调用你已编写完成的通知函数
- 兼容WebSphere日志滚动切割场景,日志被切走生成新文件时会自动定位到新的日志文件继续监听
可直接运行的完整代码
$File = "server.log" $Path = "D:\IBM\WebSphere\AppServer\profiles\AppSrv01\logs" $timeoutThreshold = New-TimeSpan -Minutes 5 $pollInterval = 10 # 轮询间隔,单位秒,可根据精度需求调整 # 定位目标日志文件 $result = Get-ChildItem $Path -Recurse | Where-Object { $_.Name -match $File } | Sort-Object LastWriteTime -Descending | Select-Object -First 1 if (-not $result) { throw "目标路径下未找到匹配的日志文件" } $currentLogPath = $result.FullName # 初始化状态变量 $lastActivityAt = Get-Date $hasSentTimeoutNotice = $false $lastReadPosition = 0 # 初始定位到文件末尾,和原代码-Tail行为对齐,不处理历史日志 $initStream = [System.IO.FileStream]::new($currentLogPath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite) $initStream.Seek(0, [System.IO.SeekOrigin]::End) | Out-Null $lastReadPosition = $initStream.Position $initStream.Close() while ($true) { Start-Sleep -Seconds $pollInterval # 日志滚动/删除检测,自动重连新日志文件 if (-not (Test-Path $currentLogPath)) { $newLog = Get-ChildItem $Path -Recurse | Where-Object { $_.Name -match $File } | Sort-Object LastWriteTime -Descending | Select-Object -First 1 if ($newLog) { $currentLogPath = $newLog.FullName $lastReadPosition = 0 $lastActivityAt = Get-Date $hasSentTimeoutNotice = $false } continue } # 读取新增日志内容 $readStream = [System.IO.FileStream]::new($currentLogPath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite) $reader = [System.IO.StreamReader]::new($readStream) $readStream.Seek($lastReadPosition, [System.IO.SeekOrigin]::Begin) | Out-Null $newContent = $reader.ReadToEnd() $lastReadPosition = $readStream.Position $reader.Close() $readStream.Close() # 处理匹配规则的新日志行 if (-not [string]::IsNullOrWhiteSpace($newContent)) { $matchedLines = $newContent -split "`r?`n" | Where-Object { $_ -match "myapp" } if ($matchedLines.Count -gt 0) { # 重置活动状态 $lastActivityAt = Get-Date $hasSentTimeoutNotice = $false # 原有日志处理逻辑 foreach ($line in $matchedLines) { "Another line was added: " + $line } } } # 超时判断 $idleDuration = (Get-Date) - $lastActivityAt if ($idleDuration -ge $timeoutThreshold -and -not $hasSentTimeoutNotice) { # ==== 此处替换为你自己编写的通知函数调用即可 ==== # 示例:Invoke-YourNotificationFunction Write-Host "检测到日志已超过5分钟无匹配活动,触发通知" # ============================================== $hasSentTimeoutNotice = $true } }
补充说明
- 超时检测的误差最大不超过你设置的轮询间隔时长,默认10秒间隔对服务器性能几乎无影响
- 通知只会在首次达到5分钟无活动阈值时触发一次,不会重复发送,直到下一次匹配的新日志写入后才会重置状态
- 代码保留了原脚本所有原有行为,不会影响你之前的日志匹配处理逻辑
内容的提问来源于stack exchange,提问作者Configueroa
相关产品推荐
相关产品推荐

