#! /usr/bin/env bash

REDIS_CLI=redis-cli
SET_SLOW_LOG_MAX_LEN="CONFIG SET slowlog-max-len %s"
GET_SLOW_LOG_MAX_LEN="CONFIG GET slowlog-max-len"
SET_SLOW_LOG_TIME="CONFIG SET slowlog-log-slower-than %s"
PORT=
PASSWORD="?"

function monitor {
    GET_SLOW_LOG="SLOWLOG GET $MAX_LENGTH"
    LAST_ID_FILE="redis_slow_query_${PORT}.id"
    printf "$SET_SLOW_LOG_MAX_LEN" $5 | $1${REDIS_CLI} -a $6 -h $2 -p $3> /dev/null
    printf "$SET_SLOW_LOG_TIME" $4 | $1${REDIS_CLI} -a $6 -h $2 -p $3 > /dev/null

    if [[ -f ./"$LAST_ID_FILE" ]] ; then
        LAST_READ_ID=$(cat ./${LAST_ID_FILE}| tr -cd "[0-9]")
    else
        LAST_READ_ID=-1
    fi

    if [[ "$LAST_READ_ID" == "" ]];then
        LAST_READ_ID=-1
    fi

    SLOW_LOG=$(echo ${GET_SLOW_LOG} | $1${REDIS_CLI} -a $6 -h $2 -p $3 -d "###")
    CURRENT_ID=$(echo "SLOWLOG GET 1" | $1${REDIS_CLI} -a $6 -h $2 -p $3} | awk 'BEGIN{FS="\n"; RS=""} {print $1}')
    LOG_LEN=$(echo "SLOWLOG LEN" | $1${REDIS_CLI} -a $6 -h $2 -p $3})
    ix=1

    while (( ix < LOG_LEN )) ; do
        jx=$((CURRENT_ID - ix))
    SLOW_LOG=$(echo -e "$SLOW_LOG" | sed "s/\(###${jx}###[[:digit:]]\{1,\}###[[:digit:]]\{1,\}###[[:alpha:]]\{1,\}\)/###\1/g")
    ix=$((ix + 1))
    done

    OUTPUT=$(echo "$SLOW_LOG" | awk 'BEGIN{RS="######";FS="###";MAX_READ_ID=-1;}

    function assemble_query(str) {

        gsub(/\|/, "<<VERTICAL>>",str);
        if(QUERY == "") {
            QUERY = str;
        } else {
            QUERY = QUERY " " str;
        }
    }

    {
        ix = 1;
        QUERY = "";
        while(ix <= NF) {
            gsub(/[[:blank:]]*/, "", $ix);
            if(ix == 1) {

                ID = $1;
                if(ID <= '$LAST_READ_ID') {
                    break;
                }
                if(ID > 'MAX_READ_ID') {
                    MAX_READ_ID=ID;
                    printf "%s<<MAX_ID>>", MAX_READ_ID;
                }
            } else if(ix == 2) {
                TIMESTAMP = $2;
            } else if(ix == 3) {
                CONSUMED_TIME = $3;
            } else {
                assemble_query($ix);
            }
            ++ix;
        }
        if(ix >= NF) {
            printf "%s<<:>>%s<<:>>%s<<###>>", TIMESTAMP, CONSUMED_TIME, QUERY;
        }
    }')
    echo $OUTPUT
    if [[ "<<:>><<:>><<###>>" != "$OUTPUT" ]] ; then
        MAX_READ_ID=$(echo ${OUTPUT} | awk 'BEGIN{FS="<<MAX_ID>>"} {print $1}' | tr -cd "[0-9]")
        if [[ "" != "$MAX_READ_ID" ]] ; then
        echo ${MAX_READ_ID} > ./${LAST_ID_FILE}
        fi
        export OUTPUT=$(echo ${OUTPUT} | awk 'BEGIN{FS="<<MAX_ID>>"} {print $2}')
    else
        OUTPUT=""
    fi
}

function usage {
    printf "\nUsage check_redis_slow_query:\n"
    printf "\t<-f redis-cli可执行程序的路径>\n"
    printf "\t[-H 设置Redis服务器的主机IP地址,默认为127.0.0.1]\n"
    printf "\t[-p 设置连接Redis服务器的端口,默认为6379]\n"
    printf "\t[-a 设置连接Redis服务器的密码,默认为空]\n"
    printf "\t[-t 设置记录Redis慢查询语句的执行时间阈值,默认为10000微秒]\n"
    printf "\t[-c 设置Redis记录慢查询语句的数目,超过此数值将删除最久的记录,默认为128]\n"
    printf "\t-h 打印帮助信息\n"
}

while getopts :f:H:p:a:t:c:h arg ; do
    case $arg in
        f) BINFOLDER=$OPTARG;;
        H) HOST=$OPTARG;;
        p) PORT=$OPTARG;;
        a) PASSWORD=$OPTARG;;
        t) THRESHOLD=$OPTARG;;
        c) MAX_LENGTH=$OPTARG;;
        h) usage
           exit 0;;
        ?) printf "无效的参数!\n"
           usage
           exit 3;;
    esac
done

if [[ ${HOST} == "" ]] ; then
    HOST=127.0.0.1
fi

if [[ ${PORT} == "" ]] ; then
    PORT=6379
fi

if [[ ${PASSWORD} == "" ]] ; then
    PASSWORD="?"
fi

if [[ ${THRESHOLD} == "" ]] ; then
    THRESHOLD=10000
fi

if [[ ${MAX_LENGTH} == "" ]] ; then
    MAX_LENGTH=128
fi

if [[ ${BINFOLDER} == "" ]] ; then
    printf "${BINFOLDER}路径下不存在可执行的redis-cli程序.\n"
    usage
    exit 3
fi

monitor ${BINFOLDER} ${HOST} ${PORT} ${THRESHOLD} ${MAX_LENGTH} ${PASSWORD}

if [[ ! -z $OUTPUT ]] ; then
    count=$(printf "%s" "$OUTPUT" | awk 'BEGIN{RS="<<###>>"} END{print NR}')
    printf "${count}<<COUNT>>|Redis_Slow_Query<<###>>%s\n" "$OUTPUT"
    exit 1
else
    exit 0
fi

发表回复

您的电子邮箱地址不会被公开。

Captcha Code