基于终端的日志工具logview

发布时间:2018-04-03
技术:shell

概述

logview是一个Shell脚本编写的基于终端的日志工具, 具有终端通知, email通知, 错误信息颜色配置, 以及灵活强大的监控配置. 还可以灵活的配置脚本监控的时间, 以及错误发生时需要进行的处理等. 该工具所使用的算法很适合监控大型日志。

详细

一、功能简介

logview 是一个Shell脚本编写的基于终端的日志工具, 具有终端通知, email通知, 错误信息颜色配置, 以及灵活强大的监控配置. 还可以灵活的配置脚本监控的时间, 以及错误发生时需要进行的处理等. 该工具所使用的算法很适合监控大型日志。该工具,居然有如下功能:

  • 脚本所采用的算法非常适合用来监视大型日志文件

  • 将所监视出的错误信息发送给指定的邮件列表

  • 可以设置监视频率,比如30s/1h扫描一次日志文件

  • 将错误信息发送到指定的tty,达到出现错误立即知晓的目的

  • 自动指定脚本从何时开始监视日志文件,以及何时结束监视

  • 自由指定错误发生时,脚本所要执行的操作,比如kill掉产生日志文件的进程等.

  • 给错误信息配色

  • 日志文件分析及生成日志报告的功能

  • 可以自由指定所要监控的报错信息

  • 只要你有bash以及mail命令即可运行此工具

二、实现方法

程序开始,global_variables用来定义一些全局变量和默认值,def_colors用来定义颜色

# load global variables
global_variables
def_colors
cat /dev/null > /tmp/logview_password.$$.log

用while来循环解析命令行参数,用shell case语法来判断不同的参数格式,不同格式不同处理:

### read cli options
# separate groups of short options. replace --foo=bar with --foo bar
while [[ -n $1 ]]; do
    case "$1" in
        -- )
            for arg in "$@"; do
                ARGS[${#ARGS[*]}]="$arg"
            done
            break
            ;;
        --debug )
            set -v
            DEBUG=0
            ;;
        --*=?* )
            ARGS[${#ARGS[*]}]="${1%%=*}"
            ARGS[${#ARGS[*]}]="${1#*=}"
            ;;
        --* )
            #die "$0: option $1 requires a value"
            ARGS[${#ARGS[*]}]="$1"
            ;;
        -* )
            for shortarg in $(sed -e 's|.| -&|g' <<< "${1#-}"); do
                ARGS[${#ARGS[*]}]="$shortarg"
            done
            ;;
        * )
            ARGS[${#ARGS[*]}]="$1"
    esac
    shift
done

set -- "${ARGS[@]}" 为解析后的最终格式:logview -a --mail-time 5h (...),这种格式可以被如下代码解析并处理:

[ "$DEBUG" -eq 0 ] && echo "DEBUG: ARGS[@]: ${ARGS[@]}"
while [[ -n $1 ]]; do
    ((args=1))
    case "$1" in
        -- )
            shift && getfilenames "$@" && break
            ;;
        -h | --help )
            Usage
            exit 0
            ;;
        -a )
            getawkfile
            exit 0
            ;;
        -m | --mail-list )
            requiredarg "$@"
            maillist="$2"
            ;;
        --max-record )
            requiredarg "$@"
            maxrecord=$2
            ;;
        -s | --scan-time )
            requiredarg "$@"
            delay=$(conv2seconds "$2")
            [ "$delay" == "unknow" ] && die "$0: Unavailable time format."
            ;;
        -l | --log-file )
            requiredarg "$@"
            loglist=$2
            ;;
        -n | --notice )
            requiredarg "$@"
            notice=$2
            ;;
        --mail-time )
            requiredarg "$@"
            mail_time=$(conv2seconds "$2")
            [ "$mail_time" == "unknow" ] && die "$0: Unavailable time format."
            ;;
        --start-time )
            requiredarg "$@"
            start_time=$2
            ;;
        --end-time )
            requiredarg "$@"
            end_time=$2
            ;;
        -r | --report )
            requiredarg "$@"
            reprot=$2
            ;;
        --format )
            requiredarg "$@"
            format=$2
            ;;
            --parse )
                requiredarg "$@"
                parse="$2"
                ;;
            --timeout-start )
                requiredarg "$@"
                timeout_start=$(conv2seconds "$2")
                [ "$timeout_start" == "unknow" ] && die "$0: Unavailable time format."
                ;;
            --timeout-end )
                requiredarg "$@"
                timeout_end=$(conv2seconds "$2")
                [ "$timeout_end" == "unknow" ] && die "$0: Unavailable time format."
                ;;
            --back-color )
                requiredarg "$@"
                back_color=\${b$2}
                ;;
            --font-color )
                requiredarg "$@"
                font_color=\${$2}
                ;;
            --font )
                requiredarg "$@"
                font=\${$2}
                ;;
            -f )
                requiredarg "$@"
                [ "$2" == "" ] && die "$0: no input file for '-f' option."
                awkfile="$2"
                ;;
            -e )
                requiredarg "$@"
                [ "$2" == "" ] && die "$0: no input file for '-f' option."
                errorfile="$2"
                ;;
            -c | --command-message )
                requiredarg "$@"
                command_message="$2"
                ;;
            -p | --print )
                print_colors
                exit 0
                ;;
            -v | --version )
                echo "$version"
                exit 0
                ;;
            -* )
                die "$0: unrecognized option '$1'"
                ;;
            *)
                getfilenames "$1"
                ;;
        esac
        shift $args
    done
    # Get log file list
    [ "$loglist" != "" ] && {
    for f in $(cat $loglist|grep -v ^#) 
    do
        #[[ -f $f ]] || die "$0: $f No such file found."
        f="$(deal_remote $f)"
        FILES[${#FILES[*]}]="$f"
    done
}

不同选项,调用不同的函数进行处理,比如:-a,会调用getawkfile函数来生成awk文件。通过调用requiredarg函数来检查--mail-time这类参数是否提供一个值,如果没有提供则报错。如果提供则把,--mail-time的值赋值给maillist变量

        -m | --mail-list )
            requiredarg "$@"
            maillist="$2"
            ;;

上面是整个脚本最核心处理复杂命令行参数的代码。接下来是监控脚本的核心代码:

logview会转存错误信息到一个文件,如果没有提供该文件,logview会打印监控到的错误信息到stdout:

[ -z "$errorfile" ] && notice=no

logview是通过调用tellb函数来通知出错信息的,如果notice=no,则不通知,如果notice=one,则调用Linux write命令将错误信息写到当前终端,如果notice=all,则logview会调用Linux wall命令将错误信息输出到所有终端。

接下来是监控脚本的核心逻辑:

通过:

while true
do
    ...
done

来循环的监控文件。

    for ((i=0;i<FILENUM;i++))
    do
        if [ "$(eval echo '$COUNT'$i)" = "" ];then
            [ -f "${MONFILES[i]}" ] &&
                eval BASE$i=$(wc -l ${MONFILES[i]} 2>/dev/null| awk '{print $1}') ||
                eval BASE$i=0
        fi
    done

该代码块功能主要是循环所有的待监控文件,并做处理。

下面的代码主要功能是:

  1. 记住上次扫描的行数

  2. 计算:下次扫描时用文件总行数 - 上次扫描的函数 = 这次需要扫描的行数。开始扫描行为上次扫描的最后一行的行number。

  3. 调用awk脚本来判断当前行是否是错误信息。

       代码会调用tail -$LINES ${MONFILES[i]}| eval "$GrepAwk"来执行指定的awk脚本,通过awk脚本判断当前行是否满足awk编写的规则。

    for ((i=0;i<FILENUM;i++))
    do
        sync_file "${MONFILES[i]}" #KONG
        [ -f "${MONFILES[i]}" ] &&
            eval COUNT$i=$(wc -l ${MONFILES[i]} | awk '{print $1}') ||
            eval COUNT$i=0
    
        #eval declare -i comp$i=0
        comp=$(($(eval echo '$COUNT'$i) - $(eval echo '$BASE'$i)))
    
        if [ $comp -gt 0 ];then
            LINES=$(eval expr '$COUNT'$i - '$BASE'$i)
            eval  BASE$i='$COUNT'$i
            IFS=$'\n'
    
            for MSGS in $(tail -$LINES ${MONFILES[i]}| eval "$GrepAwk")
            do
                [ $DEBUG -eq 0 ] && echo "DEBUG: \"error\" message is: [$MSGS]"
    
                [ -n "$MSGS" ] && {
                deal "$MSGS" "${MONFILES[i]}"
                tellb
            }
            done
        fi
    done

三、安装方法

1、准备工作

    1. 1台Linux服务器

2、安装步骤

    1. 解压logview.zip包

unzip logview.zip

    2. 进入logview目录

cd logview

    3. 复制logview文件到你的$PATH路径中

3、使用方法


    1. 获取awk过滤文件,脚本用该文件过滤错误信息,如果仅想过滤带error/failed的行,你可以执行:

logview -a

该命令会在当前目录生成名为awk.example的文件,你可以在该文件的基础上进行修改

   2. 运行./logview脚本

./logview awk.example -f test.log

    3. 更多使用方法,执行:

logview -h

    4. 举例:

  •  logview awk.example -f logfile

        该命令会每隔3s扫描一次日志文件,并将包含error或者failed单词的行输 出到标准输出.

  • 运行命令监视日志文件 - 例1

logview awk.example -f logfile --font-color=red --font=bold -s 5s -c ./command.sh -mlkong@tecent.com --mail-time=5m参数解释:

    参数解释

    -f:指定你所要监视的日志文件

    --font-color=red:将错误信息以红色字体打印

    --font=bold:字体格式为bold

    -s5s:每隔5s扫描一次日志文件

    -m:将错误信息发送给 -m参数后的maillist

    --mail-time=5m:每隔5分钟发送一次email

  • 运行命令监视日志文件 - 例2

 logview awk.example -f logfile --font-color=red --font=bold -s 5s -c ./command.sh -m lkong@redhat.com --mail-time=5m errorfile.txt --notice=one

    --notice=one:当有错误信息时,logview会将错误信息发送到你当前的tty
    --notice=all:当有错误信息时,logview会将错误信息发送到你所有的tty

四、运行效果

blob.png

blob.pngblob.png

五、压缩包文件截图

image.png

六、其他补充

其实该脚本的功能远不止这些,至于其他功能你可以参考logview -h并结合脚本源码获知其用法。该脚本很适合高频率的监视大型日志文件,假若刚启动监视脚本时是日志文件总共有10000行,设置监频率为3s,那么假设在这3s内日志文件新心曾800行,则该脚本查找错误字符串范围为10000-10800而不是0-10800,试想假若所监视的日志文件是个大型的日志文件,超过10W行,而且要不停听的监测,那么该脚本会节省很多资源和时间.而且脚本中的一些实现方法也值得学习和借鉴。当你将错误信息输出到标准输出而非文件时是,notice功能会自动被禁止掉,即使你指定了--notice参数。

本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码