用于在日志文件中验证记录器日期格式的Shell脚本

时间:2011-02-11 17:11:35

标签: shell logging

我需要验证我的日志文件:

- 所有新的日志行都应以日期开头。

- 此日期将遵守ISO 8601标准。例: 2011-02-03 12:51:45,220Z -

使用shell脚本,我可以验证它在每一行上的循环并验证日期模式。 代码如下:

#!/bin/bash

processLine(){
    # get all args
    line="$@"    
    result=`echo $line | egrep "[0-9]{4}-[0-9]{2}-[0-9]{2} [012][0-9]:[0-9]{2}:[0-9]{2},[0-9]{3}Z" -a -c`    
    if [ "$result" == "0" ]; then
        echo "The log is not with correct date format: "
        echo $line
        exit 1
    fi

}


# Make sure we get file name as command line argument
if [ "$1" == "" ]; then
   echo "You must enter a logfile"
   exit 0
else
    file="$1"
    # make sure file exist and readable
    if [ ! -f $file ]; then
        echo "$file : does not exists"
        exit 1
    elif [ ! -r $file ]; then
        echo "$file: can not read"
        exit 2
    fi
fi


# Set loop separator to end of line
BAKIFS=$IFS
IFS=$(echo -en "\n\b")
exec 3<&0
exec 0<"$file"
while read -r line
do
    # use $line variable to process line in processLine() function
    processLine $line
done
exec 0<&3

# restore $IFS which was used to determine what the field separators are
IFS=$BAKIFS
echo SUCCESS

但是,有一个问题。有些日志包含堆栈跟踪或使用多行的东西,换句话说,stacktrace就是一个例子,它可以是任何东西。 Stacktrace示例:

2011-02-03 12:51:45,220Z [ERROR] - File not found
java.io.FileNotFoundException: fred.txt
        at java.io.FileInputStream.<init>(FileInputStream.java)
        at java.io.FileInputStream.<init>(FileInputStream.java)
        at ExTest.readMyFile(ExTest.java:19)
        at ExTest.main(ExTest.java:7)
        ...

不会传递我的脚本,但有效! 然后,如果我运行我的脚本传递带有stacktraces的日志文件,我的脚本将失败,因为它逐行循环。

我有正确的模式,我需要验证记录器日期格式,但我没有错误的日期格式模式来跳过行。

我不知道如何解决这个问题。有人可以帮助我吗?

由于

4 个答案:

答案 0 :(得分:1)

您需要将搜索日期锚定到行首(否则日期可能出现在行的任何位置 - 而不仅仅是在开头)。

以下代码段将遍历以有效日期开头的所有行。您仍然需要确定这些行是否构成错误。

DATEFMT='^[0-9]{4}-[0-9]{2}-[0-9]{2} [012][0-9]:[0-9]{2}:[0-9]{2},[0-9]{3}Z'
egrep -v ${DATEFMT} /path/to/log | while read LINE; do
   echo ${LINE} # did not begin with date.
done

答案 1 :(得分:1)

所以只是(静默地)丢弃单个堆栈跟踪。在一些冗长的bash中:

STATE=idle

while read -r line; do
    case $STATE in
    idle)
        if [[ $line =~ ^java\..*Exception ]]; then
            STATE=readingexception
        else
            processLine "$line"
        fi
        ;;

    readingexception)
        if ! [[ $line =~ ^' '*'at ' ]]; then
            STATE=idle
            processLine "$line"
        fi
        ;;

    *)
        echo "Urk! internal error [$STATE]" >&2
        exit 1
        ;;
    esac
done <logfile

这依赖于processLine没有继续出错,否则你需要追踪更多状态以避免两个连续的堆栈跟踪。

答案 2 :(得分:0)

这有2个假设。

  1. 以空格开头的行是前一行的延续。我们正在匹配领先的空间或领先的标签。
  2. 从^开始的具有非空白字符的行是新的日志行。
  3. 如果匹配#2的行与日期格式不匹配,则会出现错误,因此请输入错误,并包含行号。

    count=0
    
    processLine() {
         count=$(( count + 1 ))
         line="$@"
    
         result=$( echo $line | egrep '^[0-9]{4}-[0-9]{2}-[0-9]{2} [012][0-9]:[0-9]{2}:[0-9]{2},[0-9]{3}Z' -a -c )
    
         if (( $result == 0 )); then
    
            # if result = 0, then my line did not start with the proper date.
            # if the line starts with whitespace, then it may be a continuation
            # of a multi-line log entry (like a java stacktrace)
    
            continues=$( echo $line | egrep "^ |^   " -a -c )
    
            if (( $continues == 0 )); then
    
                    # if we got here, then the line did not start with a proper date,
                    # AND the line did not start with white space.  This is a bad line.
    
                    echo "The line is not with correct date format: "
                    echo "$count: $line"
                    exit 1
            fi
        fi
    }
    

答案 3 :(得分:-1)

创建条件以检查该行是否以日期开头。如果没有,请跳过该行,因为它是多行日志的一部分。

processLine(){
    # get all args
    line="$@"    
    result=`echo $line | egrep "[0-9]{4}-[0-9]{2}-[0-9]{2} [012][0-9]:[0-9]{2}:[0-9]{2},[0-9]{3}Z" -a -c`    
    if [ "$result" == "0" ]; then
        echo "Log entry is multi-lined - continuing."
    fi

}