使用Powershell在非常大的日志文件的最后x行中搜索特定字符串

时间:2012-11-29 11:08:04

标签: perl powershell

我要求到目前为止我还没有在论坛上找到解决方案或帮助......

问题:我监控实时系统并生成一些非常大的日志文件,每天都会翻转,1GB并不罕见,我所做的是查看(尾端)日志我想监视的已知错误条件或其他字符串,我可能需要对其进行操作。

由于这类工作耗时且繁琐,并且容易因人为错误而错过日志中的问题,因此我一直在自动执行此日志文件监控。我利用名为Servers Alive的产品执行计划检查,并编写脚本来监视日志文件,以查找我感兴趣的日志条目的出现,这可能表明服务有问题,我可以调用其他脚本重新启动服务解决遇到的问题。

我以前使用Perl完成了这些日志监控任务的脚本,这些脚本非常快,但不一定是最干净的方法,我是管理员,而不是程序员所以我没有开发人员方法或经验依赖。

下面的Perl代码片段显示我打开了一个日志文件$logfile,然后从文件末尾向后搜索给定数量的数据,然后我搜索此数据指向我感兴趣监视的日志条目的文件末尾,在此示例中,日志条目为“No packet received from EISEC Client

在此示例中,我们正在监视的日志条目表明EISEC服务存在问题,并且简单地重新启动服务通常可以解决问题,所有这些我都会自动将Servers Alive用作计划检查和警报机制。 / p>

Perl脚本功能

sub checkEisecSrvloggedon {

print "$logfile\n";

if (open (EISECSRV_LOGGEDON, $logfile)) {

    seek (EISECSRV_LOGGEDON, -40000, 2);

    $line = <EISECSRV_LOGGEDON>;

    $eisecsrvloggedon_ok = 0;

    while ($line = <EISECSRV_LOGGEDON>) {   

            if ($line =~/No packet received from EISEC Client/) {

                #increment counter
                ++$eisecsrvloggedon_ok; 

                }

            }
        }
    }

我想使用PowerShell为此实现一个解决方案,如果可能的话,我们已经转移到 Windows Server 2008 R2 Windows 7 客户端,但我找不到详细介绍了如何快速有效地完成此操作,并且没有任何大量内存开销。

我尝试过基于Get-Content的解决方案但是需要读取整个日志文件会使这些类型的解决方案无法使用,因为查询日志文件需要太长时间。我需要能够定期检查一些这样的大型日志文件,在某些情况下每隔几分钟就会检查一次。我已经看到尾部类型的解决方案非常适合拖尾日志文件的末尾,这些脚本使用System.IO.File方法。这确实得到了我希望在我的脚本中实现的性能/速度,但是我对 PowerShell 不熟悉,知道如何使用这种方法快速到达大型日志文件的末尾,并且然后能够向后读取给定数量的数据,然后在此日志部分中搜索相关字符串。

有没有人有任何想法?

3 个答案:

答案 0 :(得分:5)

如果您使用PowerShell 3.0或更高版本,则可以使用get-contentselect-string命令行开关的组合来获得相同的功能。自版本3.0起,get-content支持-tail选项,该选项仅以有效的方式返回文件的最后 n 行。使用此方法,您可以使用以下内容重新实现上面的Perl脚本(在最后1000行中搜索):

# Returns the number of occurrences
(get-content logfile.txt -Tail 1000 | select-string -pattern "No packet received from EISEC Client").Length

答案 1 :(得分:2)

要向后搜索,this contribution to the Poshcode repository似乎非常符合您的要求:

# Name: Get-Tail.ps1
# Author: William Stacey
# Created: 02/22/2007
# Description: Gets the last N lines of a file. Does scan from end-of-file so works on large files. Also has a loop flag that prompts for refresh.

function Get-Tail([string]$path = $(throw "Path name must be specified."), [int]$count = 10, [bool]$loop = $false)
{
    if ( $count -lt 1 ) {$(throw "Count must be greater than 1.")}
    function get-last
    {
        $lineCount = 0
        $reader = new-object -typename System.IO.StreamReader -argumentlist $path, $true
        [long]$pos = $reader.BaseStream.Length - 1

        while($pos -gt 0)
        {
            $reader.BaseStream.Position = $pos
            if ($reader.BaseStream.ReadByte() -eq 10)
            {
                if($pos -eq $reader.BaseStream.Length - 1)
                {
                    $count++
                }
                $lineCount++
                if ($lineCount -ge $count) { break }
            }
            $pos--
        } 

        if ($lineCount -lt $count)
        {
            $reader.BaseStream.Position = 0
        }

        while($line = $reader.ReadLine())
        {
            $lines += ,$line
        }

        $reader.Close()
        $lines
    }

    while(1)
    {
        get-last
        if ( ! $loop ) { break }
        $in = read-host -prompt "Hit [Enter] to tail again or Ctrl-C to exit"
    }
}

答案 2 :(得分:1)

PSCX有一个名为Get-FileTail的cmdlet,它可以有效地获取文件的最后几行,从而避免事先读取整个文件。