【问题标题】:Powershell log tailer issuesPowershell 日志尾部问题
【发布时间】:2015-05-19 07:37:42
【问题描述】:

我用 Powershell 编写了一个日志tailer,tailer 加载到一个 xml 文件中,该文件包含有关何时报告日志尾部中的单词匹配的配置信息(基本上,如果某些模式在尾部出现 X 次)。

目前,tailer 没有为许多包含匹配项的行返回匹配项。

例如,我们正在检索一个包含许多 INFO 行的日志文件,如果我检查单词 INFO 没有检测到任何东西,但是如果我查找工作 shutdown 它返回匹配项(带有 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,但是测试服务器也运行相同的版本非常好......

【问题讨论】:

  • 这就是重现您的问题所需的全部内容吗?如果您怀疑版本可能是一个因素,最好包含相关版本。
  • 乍一看,您可能对变量范围有疑问。较新版本的 PoweShell (v3,v4) 对变量范围有更严格的限制(仅我的轶事经验)。特别要检查 $keywords 和 $maxCounts 是否可以在函数 LoadLogTailerConfig 中实际访问。这可能因 PowerShell 版本而异。
  • @JanChrbolka 如果是这种情况,虽然我不应该有任何关键字得到匹配,但是其中一些得到匹配,而同一行上的其他关键字没有被检测到......
  • 您能在问题中添加一个简短的示例日志文件吗?
  • @JanChrbolka 可能不是一个好主意,因为它可能会带来安全风险,但是它们确实是相当标准的日志,它们具有以下格式: 其中 LogType 是 INFO错误调试等和消息包含异常或其他信息

标签: regex xml powershell


【解决方案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。

【讨论】:

  • 这很奇怪,因为我们在测试服务器上运行它并且它工作得非常好,但它只运行 1.0,我会尝试进行升级,看看它是否有任何不同。
  • 您是否使用 $PSVersionTable 变量检查过 PS 的版本?我已经修改了答案。
  • 我会检查一下,我怀疑你对我的问题有正确的答案
  • 看起来测试服务器运行的是 PS 3,而生产服务器运行的是 2
猜你喜欢
  • 1970-01-01
  • 2013-02-22
  • 2015-11-11
  • 2014-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 2021-11-05
相关资源
最近更新 更多