我的公司需要分析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)
不幸的是,人们不能说会出现多少行这样的错误。因此100只是一个估计(效果很好)。
那么如何更改相关的行
$request = Get-Content ($logFile) | select -last 100 |
where { $_ -match $errorName -and $_ -gt $logTimeStart }
到正确的一个?
答案 0 :(得分:1)
使用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})
与时间戳匹配
(\w+)
符合严重程度
(.*(?:\n\D.*)*)
匹配日志消息(当前行后跟零行或多行不以数字开头)。
每个子表达式周围的括号将子匹配捕获为一个组,然后可以用它来填充自定义对象的属性。
$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及更高版本中,可以通过使用参数Get-Content
调用-Raw
来实现。在早期版本中,您可以通过Get-Content
cmdlet管道Out-String
的输出以获得相同的结果:
Get-Content $file | Out-String | ...