我已经使用Powershell编写了一个日志记录器,该文件包加载在一个xml文件中,该文件包含有关何时在日志尾部报告单词匹配的配置信息(基本上如果某些模式在尾部出现X次)。
目前,该帖子没有为包含匹配项的许多行返回匹配项。
例如,我们正在检索具有许多INFO行的日志文件,如果我检查单词INFO没有检测到任何内容,但是如果我查找工作关闭它返回匹配(带有shutdown的行也包含行上的INFO) 。
真正奇怪的是,使用相同的日志文件和相同的Powershell脚本似乎可以在我自己的机器上生成完全准确的结果,但在服务器上表现得很奇怪。
我怀疑这可能是服务器上运行的Powershell版本的一个问题,所以我希望这里有人可能知道可以提出不同版本的问题。我还注意到,当我打印出匹配的数量时,如果没有找到任何结果,输出是空白的,也许这应该是0并导致一些奇怪的问题被触发?
function Main()
{
#### GLOBAL SETTINGS
$DebugPreference = "Continue"
$serverName = $env:COMPUTERNAME
$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path
$logConfigPath = "$scriptPath/config.xml"
#### VARIABLES RELATING TO THE LOG FILE
#contains the log path and log file mask
$logPaths = @()
$logFileMasks = @()
# the total number of lines grabbed from the end of the log file for evaluation
$numLinesToTail = 1000
# key value pair for the strings to match and the max count of matches before they are considered an issue
$keywords = @()
$maxCounts = @()
#### VARIABLES RELATING TO THE EMAIL SETTINGS
$smtpServer = "mail server"
$emailSubject = "$serverName log report"
$toEmailAddress = "email accounts"
$fromEmailAddress = ""
# any initial content you want in the email body should go here (e.g. the name of the server that this is on)
$htmlBodyContent = "<p><h3>SERVER $serverName : </h3></p><p>Items that appear in red have exceeded their match threshold and should be investigated.<br/>Tail Lines: $numLinesToTail</p>"
#### FUNCTION CALLS
LoadLogTailerConfig $logConfigPath ([ref]$logPaths) ([ref]$logFileMasks) ([ref]$keywords) ([ref]$maxCounts)
for ($i = 0; $i -lt $logPaths.Count; $i++)
{
$tail = GetLogTail $numLinesToTail $logPaths[$i] $logFileMasks[$i]
$tailIssueTable = CheckForKeywords $tail $keywords[$i] $maxCounts[$i]
if ($tailIssueTable -ne "")
{
$htmlBodyContent += "<br/>Logs scanned: " + (GetLatestLogFileFullName $logPaths[$i] $logFileMasks[$i]) + "<br/><br/>" + $tailIssueTable
SendIssueEmail $smtpServer $emailSubject $toEmailAddress $ccEmailAddress $fromEmailAddress $htmlBodyContent
}
}
}
# Loads in configuration data for the utility to use
function LoadLogTailerConfig($logConfigPath, [ref]$logPaths, [ref]$logFileMasks, [ref]$keywords, [ref]$maxCounts)
{
Write-Debug "Loading config file data from $logConfigPath"
[xml]$configData = Get-Content $logConfigPath
foreach ($log in $configData.Logs.Log) {
$logPaths.Value += $log.FilePath
$logFileMasks.Value += $log.FileMask
$kwp = @()
$kwc = @()
foreach ($keywordSet in $log.Keywords.Keyword)
{
$kwp += $keywordSet.Pattern
$kwc += $keywordSet.MaxMatches
}
$keywords.Value += @(,$kwp)
$maxCounts.Value += @(,$kwc)
}
}
# Gets a string containing the last X lines of the most recent log file
function GetLogTail($numLinesToTail, $logPath, $logFileMask)
{
$logFile = GetLatestLogFileFullName $logPath $logFileMask #Get-ChildItem $logPath -Filter $logFileMask | sort LastWriteTime | select -Last 1
Write-Debug "Getting $numLinesToTail line tail of $logFile"
$tail = Get-Content "$logFile" | select -Last $numLinesToTail
return $tail
}
function GetLatestLogFileFullName($logPath, $logFileMask)
{
$logFile = Get-ChildItem $logPath -Filter $logFileMask | sort LastWriteTime | select -Last 1
return "$logPath$logFile"
}
# Returns body text for email containing details on keywords in the log file and their frequency
function CheckForKeywords($tail, $keywords, $maxCounts)
{
$issuesFound = 0
$htmlBodyContent += "<table><tr><th style=""text-align : left;"">Keyword</th><th>Max Count Value</th><th>Count Total<th></tr>"
for ($i = 0; $i -lt $keywords.Count; $i++)
{
$keywordCount = ($tail | Select-String $keywords[$i] -AllMatches).Matches.Count
Write-Debug (("Match count for {0} : {1}" -f $keywords[$i], $keywordCount))
if ($keywordCount -gt $maxCounts[$i])
{
# style red if the count threshold has been exceeded
$htmlBodyContent += "<tr style=""color : red;""><td>" + $keywords[$i] + "</td><td>" + $maxCounts[$i] + "</td><td>" + $keywordCount + "</td></tr>"
$issuesFound = 1
}
else
{
# style green if the count threshold has not been exceeded
$htmlBodyContent += "<tr style=""color : green;""><td>" + $keywords[$i] + "</td><td>" + $maxCounts[$i] + "</td><td>" + $keywordCount + "</td></tr>"
}
}
$htmlBodyContent += "</table>"
if ($issuesFound -eq 1)
{
return $htmlBodyContent
}
return ""
}
# Sends out an email to the specified email address
function SendIssueEmail($smtpServer, $subject, $toAddress, $ccAddress, $fromAddress, $bodyContent)
{
Write-Debug "Sending email with subject: $subject, To: $toAddress, via SMTP ($smtpServer)"
Send-MailMessage -SmtpServer $smtpServer -Subject $subject -To $toAddress -From $fromAddress -BodyAsHtml $bodyContent
}
cls
Main
一个XML配置示例:
<Logs>
<Log>
<FilePath>C:/Some/Path</FilePath>
<FileMask>log.*</FileMask>
<Keywords>
<Keyword>
<Pattern>NullReferenceException</Pattern>
<MaxMatches>10</MaxMatches>
</Keyword>
<Keyword>
<Pattern>Exception</Pattern>
<MaxMatches>10</MaxMatches>
</Keyword>
</Keywords>
</Log>
<Log>
<FilePath>C:/Some/Path</FilePath>
<FileMask>test.*</FileMask>
<Keywords>
<Keyword>
<Pattern>NullReferenceException</Pattern>
<MaxMatches>100</MaxMatches>
</Keyword>
</Keywords>
</Log>
</Logs>
编辑:遇到问题的服务器正在运行Powershell V 1.0,但测试服务器也运行相同的版本完全正常......
答案 0 :(得分:1)
您的函数GetLatestLogFileFullName是一个问题。它可以并且将生成无效路径。
function GetLatestLogFileFullName($logPath, $logFileMask)
{
$logFile = Get-ChildItem $logPath -Filter $logFileMask | sort LastWriteTime | select -Last 1
return "$logPath$logFile"
}
请改用:
return $logfile.FullName
您还应该检查没有有效日志文件的情况:
if ($logfile) {
return $logfile.FullName
} else {
return $null
}
第二个问题是你的Select-String用法。
$keywordCount = ($tail | Select-String $keywords[$i] -AllMatches).Matches.Count
在PowerShell v1中,Select-String没有-AllMatches参数。
PS> Get-Help Select-String
NAME
Select-String
SYNOPSIS
Identifies patterns in strings.
SYNTAX
Select-String [-pattern] <string[]> -inputObject <psobject>[-include <string[]>] [-exclude <string[]>] [-simpleMatch] [-caseSensitive] [-quiet] [-list] [<CommonParameters>]
Select-String [-pattern] <string[]> [-path] <string[]> [-include<string[]>] [-exclude <string[]>] [-simpleMatch] [-caseSensitive] [-quiet] [-list] [<CommonParameters>]
使用$ PSVersionTable变量检查服务器上的PowerShell版本。不要依赖标题栏中显示的版本!
如果变量不存在,则您拥有版本1。