我的公司需要分析 Tomcat 的日志文件以检查特定错误并使用 Powershell。这些错误将存储在一个数组中,并按 1:1 进行检查。这通过使用 Windows 任务计划程序每 30 分钟发生一次。如果在日志文件中发现此类错误,则会将生成的文本文件发送给管理员。
然而,只有在最后 30 分钟内检查错误才有意义,而不是事先检查错误。
所以我先定义了一个时间变量:
$logTimeStart = (Get-Date).AddMinutes(-30).ToString("yyyy-MM-dd HH:mm:ss")
稍后我检查是否存在这样的错误:
$request = Get-Content ($logFile) | select -last 100 | where { $_ -match $errorName -and $_ -gt $logTimeStart }
不幸的是,这不起作用;它还发送在此 30 分钟间隔之前发生的错误。
这是 Tomcat 日志的摘录:
2016-05-25 14:21:30,669 FATAL [http-apr-8080-exec-4] admins@company.de de.abc.def.business.service.ExplorerService GH00000476: de.abc.def.business.VisjBusinessException: Invalid InstanceId at de.abc.def.business.service.ExplorerService$ExplorerServiceStatic.getExplorer(ExplorerService.java:721) at de.abc.def.business.service.ExplorerService$ExplorerServiceStatic.getTreeItemList(ExplorerService.java:823) at sun.reflect.GeneratedMethodAccessor141.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at de.abc.def.business.provider.ServiceProvider.callServiceMethod(ServiceProvider.java:258) at de.abc.def.business.communication.web.client.ServiceDirectWrapperDelegate.callServiceMethod(ServiceDirectWrapperDelegate.java:119) at de.abc.def.business.communication.web.client.ServiceWrapperBase.callServiceMethod(ServiceWrapperBase.java:196) at de.abc.def.business.communication.web.client.ServiceDirectWrapper.callServiceMethod(ServiceDirectWrapper.java:24) at de.abc.def.web.app.service.stub.AbstractBaseStub.callServiceMethodDirect(AbstractBaseStub.java:72) at de.abc.def.web.app.service.stub.AbstractBaseStub.callServiceMethod(AbstractBaseStub.java:183) at de.abc.def.web.app.service.stub.StubSrvExplorer.getTreeItemList(StubSrvExplorer.java:135) at de.abc.def.web.app.resource.servlet.ExplorerServlet.createXml(ExplorerServlet.java:350) at de.abc.def.web.app.resource.servlet.ExplorerServlet.callExplorerServlet(ExplorerServlet.java:101) at de.abc.def.web.app.resource.servlet.VisServlet.handleServlets(VisServlet.java:244) at de.abc.def.web.app.FlowControlAction.isPing(FlowControlAction.java:148) at de.abc.def.web.app.FlowControlAction.execute(FlowControlAction.java:101) at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:484) at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274)
Unfortunately one cannot say how many lines of such an error will show up. Therefore 100 is just an estimate (which works well).
So how to change the related line
$request = Get-Content ($logFile) | select -last 100 |
where { $_ -match $errorName -and $_ -gt $logTimeStart }
一个正确的?
最佳答案
使用Select-String
和正则表达式来解析您的日志文件。基本上,日志条目由时间戳、严重性和消息(可能跨越多行)组成。正则表达式可能如下所示:
(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\s+(\w+)\s+(.*(?:\n\D.*)*(?:\n\t.*)*)
(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})
matches the timestamp.
(\w+)
matches the severity.
(.*(?:\n\D.*)*)
matches the log message (the current line followed by zero or more lines not beginning with a number).
The parentheses around each subexpression capture the submatch as a group that can then be used for populating the properties of custom objects.
$datefmt = 'yyyy-MM-dd HH:mm:ss,FFF'
$culture = [Globalization.CultureInfo]::InvariantCulture
$pattern = '(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\s+(\w+)\s+(.*(?:\r\n\D.*)*)'
$file = 'C:\path\to\your.log'
Get-Content $file -Raw | Select-String $pattern -AllMatches | ForEach-Object {
$_.Matches | ForEach-Object {
New-Object -Type PSObject -Property @{
Timestamp = [DateTime]::ParseExact($_.Groups[1].Value, $datefmt, $culture)
Severity = $_.Groups[2].Value
Message = $_.Groups[3].Value
}
}
}
将日期子字符串解析为 DateTime
值实际上并不是必需的(因为即使使用字符串比较也可以正确排序 ISO 格式的日期字符串),但这样做很好,所以您不需要必须将您的引用时间戳转换为格式化字符串。
请注意,您需要将整个日志文件作为单个字符串来读取才能工作。在 PowerShell v3 和更新版本中,这可以通过使用参数 -Raw
调用 Get-Content
来实现。在早期版本中,您可以将 Get-Content
的输出通过 Out-String
cmdlet 进行管道传输以获得相同的结果:
Get-Content $file | Out-String | ...
关于powershell - 在日志文件中查找大于定义时间的条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37437422/