【问题标题】:Scanning the log files for last 30 minutes of data扫描日志文件以获取最近 30 分钟的数据
【发布时间】:2015-01-18 04:23:10
【问题描述】:

我必须编写一个 shell/perl 脚本来扫描一个日志文件以获取最后 30 分钟的数据。要求是在 Cron 中安排此脚本每 30 分钟运行一次并查找错误字符串。

OS: Solaris
Shell:Bash

我试过下面的脚本,但它变得太长而且笨拙,我们有其他方法可以让它更短吗?

blogs=/opt/docs/datapower/prod/business.log
slogs=/opt/docs/datapower/prod/system.log


starttime=$(date +'%H')
currmin=$(date +'%M')
curdate=`date|cut -d' ' -f5`
echo $(date)

if [ $currmin -le 29 ] && [ $starttime -ne 00 ] ; then
starttime1=`echo "$(date +'%H') - 1" | bc`
logtime="$starttime1"
logtime="$logtime:[3-5][0-9]"
echo $logtime



elif [ $currmin -le 29 ] && [ $starttime -eq 00 ] ; then
logtime="23:[3-5][0-9]"
echo $logtime



else
logtime="$starttime"
logtime="$logtime:[0-2][0-9]"
echo $logtime

fi

if ( grep "$logtime" $slogs | egrep "AAA Authentication Failure|AAA Authorization Failure") > dptest 2>&1;then

       Do something

fi 

更新:添加示例日志语句。 以下是日志语句的示例: Nov 20 06:06:58 business-log-sta [DP-Domain-STAGING][0x80000001][business-log][info] mpgw(GenServiceMPG): trans(31513092)[request]: AAA Authentication failure/>

【问题讨论】:

  • 你能举个例子吗?
  • 问题中添加了示例日志行。
  • 只是一个疯狂的猜测,带有 perl 5.8.x 的 Solaris 所以没有安装 Time::Piece 模块。
  • 在 Solaris 中测试 date 命令。如果它像 Linux date 这样通用,您可以减少 IF-THEN-ELSE 块并使其更容易。

标签: bash perl shell solaris perlscript


【解决方案1】:

我认为你做的有点倒退 - 构建一个 RE 以从日志文件中 grep 日期。

在 perl 中处理这个问题,我希望读取整个日志文件,将其标记化 - 以提取时间戳 - 然后根据消息内容发出警报。

Perl 的第一部分有一个不错的模块 - Time::Piece。 有点像这样:

use strict;
use warnings;

use Time::Piece;

my $HALF_HOUR = 30 * 60;

while (<DATA>) {
    #extract timestamp via regular expression
    my ( $timestamp, $message ) = (m/\A(\w+\s+\d+\s+\d+:\d+:\d+) (.*)/);

    #convert text timestamp to 'unix time'. 
    #need the year in here because your log doesn't include it. 
    my $t = localtime();
    $t = $t->strptime( $timestamp . " " . $t->year, "%b %d %H:%M:%S %Y" );


    #skip if parsed time is more than half an hour ago. 
    next if ( $t < time() - $HALF_HOUR );
    if (   $message =~ m/AAA Authentication failure/i
        or $message =~ m/AAA Authorization failure/i )
    {
        print "Alert: ( $t )  $message\n";
    }
}

__DATA__
Nov 20 13:46:58 business-log-sta [DP-Domain-STAGING][0x80000001][business-log][info] mpgw(GenServiceMPG): trans(31513092)[request]: AAA Authentication failure/>
Nov 20 13:00:58 business-log-sta [DP-Domain-STAGING][0x80000001][business-log][info] mpgw(GenServiceMPG): trans(31513092)[request]: AAA Authentication failure/>
Nov 20 10:06:58 business-log-sta [DP-Domain-STAGING][0x80000001][business-log][info] mpgw(GenServiceMPG): trans(31513092)[request]: AAA Authentication failure/>

后续问题:

“你能解释一下这个语句的作用吗,my ( $timestamp, $message ) = (m/\A(\w+\s+\d+\s+\d+:\d+:\d+) (.*)/);

这做了两件事:

  • Perl 中的一个技巧是,您可以捕获正则表达式的一部分,方法是将其放在括号中。所以 \A(\w+\s+\d+\s+\d+:\d+:\d+) - 将从行首开始匹配:
    • 一个或多个“单词”字符。
    • 一个或多个“数字”
    • \d+:\d+:\d+ 将捕获时间。 (任何 3 个冒号分隔的数字)。

当然,另一部分捕捉“其余部分”。

  • 然后,我们将模式匹配返回的数组分配给命名变量数组($timestamp$message)。

净结果是 - 给定行:

 Nov 20  13:46:58       business-log-sta [DP-Domain-STAGING][0x80000001][business-log][info] mpgw(GenServiceMPG): trans(31513092)[request]: AAA Authentication failure/>
(\w+ \d+ \d+:\d+:\d+)   (.*)

我们的正则表达式分别返回两个“块”,然后我们将它们放入两个变量中。

【讨论】:

  • 你能解释一下这个语句的作用吗,my ( $timestamp, $message ) = (m/\A(\w+\s+\d+\s+\d+:\d+:\d+) (.*)/);
  • 谢谢,现在我不必每半小时在日志中搜索一次错误,而是必须找到一个字符串并将其发送到日志文件。我在shell脚本中做过这样的事情。 grep 'BIRCH' $blogs|sed -e 's/BIRCH//' &gt; /tmp/dp/ORIGO_CE_MI 。如何在 perl 中实现这一点?我正在日志中搜索名为 BIRCH 的字符串并发送包含字符串的行匹配,但没有复制此特定字符串(使用 sed)。
【解决方案2】:

您如何看待使用 sqlite3 进行过滤 - 它为您解析时间的好处可能非常方便。 唯一的缺点是您必须对数据进行规范化。

function sqlite-filter-time() {
    if [ '0' = "$#" ]; then
        echo "Usage: $FUNCNAME <file> <timespan> <where>"
        return
    fi
    local year="$(date '+%Y')"
    local ofs='___FS___'
    sed  "s,^\([^ ]* [^ ]*\) \([^ ]*\),\1 \2$ofs," "$1" | sed "s,Jan ,$year-01-,;s,Feb ,$year-02-,;s,Mar ,$year-03-,;s,Apr ,$year-04-,;s,May ,$year-05-,;s,June ,$year-06-,;s,July ,$year-07-,;s,Aug ,$year-08-,;s,Sep ,$year-09-,;s,Oct ,$year-10-,;s,Nov ,$year-11-,;s,Dec ,$year-12-," > "$1.tmp" # normalize data for sqlite - command to extract the date and the rest of the text
    {
        echo '.mode csv'
        echo 'DROP TABLE IF EXISTS sft;'
        echo 'CREATE TEMPORARY TABLE sft ('
        echo '  sft_date TEXT,'
        echo '  sft_text TEXT'
        echo ');'
        echo ".headers off"
        echo ".nullvalue ''"
        echo ".separator '$ofs'"
        echo ".import $1.tmp sft"
        echo ".separator ' '"
        echo "SELECT *"
        echo "FROM sft"
        echo "WHERE sft_date > datetime('now', '$2')"
        echo " AND (sft_text like '%AAA Authentication Failure%'"
        echo "   OR sft_text like '%AAA Authorization Failure%'"
        echo " )"
        echo ";"
    } | sqlite3
    rm "$1.tmp"
}

$ sqlite-filter-time "$slogs" '-30 minutes'
"2014-11-20 16:01:58" " business-log-sta [DP-Domain-STAGING][0x80000001][business-log][info] mpgw(GenServiceMPG): trans(31513092)[request]: AAA Authentication failure/>"
$

【讨论】:

    猜你喜欢
    • 2012-03-16
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 2019-06-03
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多