原创

CentOS-查询实时报错日志-查询前1天业务报错gz压缩日志

1. 查询实时报错日志

物理路径(带*的放在靠后,或者不用*

cd /home/logs/java-gz-log-dir && tail -2000f java-gz-log-dir-error.log | grep -ivE '(登录失败|不包含|不合法|不匹配|存在|未在系统中|入参无效|没有【生效中】|找不到|重复|JwtToken|已过期|catalina|token 为空|被踢出|Broken pipe|ErrorPage|Servlet\.service\(\) for servlet \[dispatcherServlet\]|无*数据)' | grep -iE -C 30 '(timeout|PSQLException: ERROR|ERROR|失败|EOFException|SocketException|IOException|sql执行出现异常|不判定为缺失)'

docker版本(带*的放在靠后,或者不用*

docker logs --tail 20000 --follow java-gz-log-dir | grep -ivE '(登录失败|不包含|不合法|不匹配|存在|未在系统中|入参无效|没有【生效中】|找不到|重复|JwtToken|已过期|catalina|token 为空|被踢出|Broken pipe|ErrorPage|Servlet\.service\(\) for servlet \[dispatcherServlet\]|无*数据)' | grep -iE -C 20 '(timeout|PSQLException: ERROR|ERROR|失败|EOFException|SocketException|IOException|sql执行出现异常|监测点|不判定为缺失)'

2. 查询前1天业务报错gz压缩日志

2.1 简化版

cd /home/logs/java-gz-log-dir && [ -d "/home/logs/java-gz-log-dir/lastDayErrorLog" ] || mkdir /home/logs/java-gz-log-dir/lastDayErrorLog && rm -f /home/logs/java-gz-log-dir/lastDayErrorLog/* && echo "开始复制昨天的错误日志文件" && cp $(ls -t java-gz-log-dir-error.log.*.gz | head -1) lastDayErrorLog && cd ./lastDayErrorLog && echo "开始解压错误日志文件" && gunzip *.gz && echo "开始查找错误日志文件内容" && cat * | grep -ivE '(登录失败|不包含|不合法|不匹配|存在|未在系统中|入参无效|没有【生效中】|找不到|重复|JwtToken|已过期|catalina|token 为空|被踢出|Broken pipe|ErrorPage|Servlet\.service\(\) for servlet \[dispatcherServlet\]|无*数据)' | grep -iE -C 30 '(timeout|PSQLException: ERROR|ERROR|失败|EOFException|SocketException|IOException|sql执行出现异常|监测点|不判定为缺失)' || true && \
echo "查找完成"

2.2 完整版带上下文(不能过滤相邻行错误日志会显示出2条)【不推荐】

#!/bin/bash

clear && \
log_dir="/home/logs/java-gz-log-dir" && \
log_file="java-gz-log-dir-error.log.*.gz" && \
latest_log=$(ls -t $log_dir/$log_file | head -1) && \
if [ -z "$latest_log" ]; then
    echo "未找到需要复制的日志文件"
    exit 0
fi && \
cd "$log_dir" && \
[ -d "$log_dir/lastDayErrorLog" ] || mkdir "$log_dir/lastDayErrorLog" && \
rm -f "$log_dir"/lastDayErrorLog/* && \
echo "开始复制昨天的错误日志文件: $latest_log" && \
echo "开始复制昨天的错误日志文件: $latest_log" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
cp "$latest_log" "$log_dir/lastDayErrorLog" && \
cd "$log_dir/lastDayErrorLog" && \
echo "开始解压错误日志文件"  && \
echo "开始解压错误日志文件" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
gunzip -c *.gz > unzip_file.log || { echo "解压失败"; exit 1; } && \
echo "确认当前文件夹下文件:" && \
echo "确认当前文件夹下文件:" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
ls -lsh >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
echo "开始查找错误日志文件内容;$(ls -t ./*)"  && \
echo "开始查找错误日志文件内容;$(ls -t ./*)" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
total_lines=$(cat * | wc -l) && \
# 控制打印10次进度日志
print_interval=$((total_lines / 10)) && \
output_file="$log_dir/lastDayErrorLog/error_analysis_result.log" && \
>> "$output_file" && \
echo "请确认以上文件信息,3秒后开始查找..." && \
sleep 3 && \
awk -v total_lines="$total_lines" -v print_interval="$print_interval" '
    BEGIN {
        context = 100; # 设置上下文为100行
        line_count = 0; # 记录当前处理的行数
        RED = "\033[38;5;196m"; # 红色
        BLUE = "\033[34m"; # 蓝色
        RESET = "\033[0m"; # 重置颜色
    }
    {
        # 跳过空白行
        if (NF == 0) {
            next;
        }

        # 打印提示信息
        if (line_count % print_interval == 0) {
            print "继续查找中... 当前行号:", NR, "/ 总行数:", total_lines;
        }
        line_count++;

        # 缓存所有行,不删除任何内容
        lines[NR] = $0;

        # 忽略不相关的行
        if ($0 ~ /登录失败|不包含|不合法|不匹配|存在|未在系统中|入参无效|没有【生效中】|找不到|重复|JwtToken|已过期|catalina|token 为空|被踢出|Broken pipe|ErrorPage|Servlet\.service$$ for servlet $dispatcherServlet$|无*数据/) {
            next;
        }

        # 缓存所有行,不删除任何内【应该提前,不然上下文不连续】
        # lines[NR] = $0;

        # 匹配目标关键字并记录命中行号
        if ($0 ~ /timeout|PSQLException: ERROR|ERROR|失败|EOFException|SocketException|IOException|sql执行出现异常|不判定为缺失/) {
            hit_lines[NR] = 1; # 记录命中行号
        }
    }
    END {
        # 将命中行号存储到数组中以便排序
        n = 0;
        for (hit_nr in hit_lines) {
            sorted_hits[++n] = hit_nr+0; # 强制转为数值
        }

        # 手动实现冒泡排序(适用于所有 awk 实现)
        for (i = 1; i <= n; i++) {
            for (j = i + 1; j <= n; j++) {
                if (sorted_hits[i] > sorted_hits[j]) {
                    temp = sorted_hits[i];
                    sorted_hits[i] = sorted_hits[j];
                    sorted_hits[j] = temp;
                }
            }
        }

        # 遍历排序后的命中行号,打印上下文
        for (i = 1; i <= n; i++) {
            hit_nr = sorted_hits[i];

            printf("\n\n-----------------------错误序号: %d------------------------------\n", i);
            printf("\n\n-----------------------错误序号: %d------------------------------\n", i) >> "'"$output_file"'";

            # 打印命中行(红色高亮)
            printf("%s命中关键字: 命中行号 %d%s\n", RED, hit_nr, RESET);
            printf("%s%s%s\n", RED, lines[hit_nr], RESET); # 打印命中行,使用红色高亮

            # 写入文件:命中行
            printf("命中关键字: 命中行号 %d\n", hit_nr) >> "'"$output_file"'";
            printf("%s\n", lines[hit_nr]) >> "'"$output_file"'";

            # 打印上下文范围提示
            print (hit_nr > context ? "..." : ""), (hit_nr-context > 0 ? hit_nr-context : 1), "<--命中前后上下文-->", hit_nr+context, "...";

            # 写入文件:上下文范围提示
            printf((hit_nr > context ? "...\n" : ""), (hit_nr-context > 0 ? hit_nr-context : 1), "<--命中前后上下文-->", hit_nr+context, "...") >> "'"$output_file"'";

            # 打印上下文行
            for (j = hit_nr-context; j <= hit_nr+context; j++) {
                if (j in lines && length(lines[j]) > 0 && j >= 1) { # 确保 j 在有效范围内
                    if (j == hit_nr) {
                        # 当前行是命中行,打印红色
                        printf("%s【当前为命中行,堆栈看下文,行号:%d】 %s%s\n", RED, j, lines[j], RESET);
                        # 写入文件:命中行上下文
                        printf("【当前为命中行,堆栈看下文,行号:%d】 %s\n", j, lines[j]) >> "'"$output_file"'";
                    } else if (lines[j] ~ /cn.jiangjiesheng|otherkeyword/) {
                        # 当前行包含指定关键词,打印蓝色
                        printf("%s[行号:%d] %s%s\n", BLUE, j, lines[j], RESET);
                        # 写入文件:关键词上下文
                        printf("[行号:%d] %s\n", j, lines[j]) >> "'"$output_file"'";
                    } else {
                        # 其他行是上下文行,打印默认颜色
                        printf("[行号:%d] %s\n", j, lines[j]);
                        # 写入文件:其他上下文
                        printf("[行号:%d] %s\n", j, lines[j]) >> "'"$output_file"'";
                    }
                }
            }
        }
    }
' unzip_file.log || true && \
echo " " && \
echo " " >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
echo "查找完成,准备删除解压文件" && \
echo "查找完成,准备删除解压文件" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
find "$log_dir/lastDayErrorLog" -maxdepth 1 -type f ! -name '*result*' -exec rm -f {} \; && \
echo "删除解压文件完成,执行ls -lsh结果" && \
echo "删除解压文件完成,执行ls -lsh结果" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
ls -lsh && \
ls -lsh >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
echo "是否下载分析结果文件 error_analysis_result.log? 输入 y 确认,其他键跳过【适用XShell,后期可以改成小文件不压缩】: " && \
read user_input && \
if [ "$user_input" = "y" ]; then
    tar -zcvf error_analysis_result.log.tar.gz error_analysis_result.log
    sz error_analysis_result.log.tar.gz || echo "文件下载失败,请检查环境是否支持 sz 命令。"
else
    echo "跳过文件下载。"
fi

2.2 完整版(过滤相邻行错误日志,并显示下文)【推荐】

#!/bin/bash

clear && \
log_dir="/home/logs/java-gz-log-dir" && \
log_file="java-gz-log-dir-error.log.*.gz" && \
latest_log=$(ls -t $log_dir/$log_file | head -1) && \
if [ -z "$latest_log" ]; then
    echo "未找到需要复制的日志文件"
    exit 0
fi && \
cd "$log_dir" && \
[ -d "$log_dir/lastDayErrorLog" ] || mkdir "$log_dir/lastDayErrorLog" && \
rm -f "$log_dir"/lastDayErrorLog/* && \
echo "开始复制昨天的错误日志文件: $latest_log" && \
echo "开始复制昨天的错误日志文件: $latest_log" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
cp "$latest_log" "$log_dir/lastDayErrorLog" && \
cd "$log_dir/lastDayErrorLog" && \
echo "开始解压错误日志文件"  && \
echo "开始解压错误日志文件" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
gunzip -c *.gz > unzip_file.log || { echo "解压失败"; exit 1; } && \
echo "确认当前文件夹下文件:" && \
echo "确认当前文件夹下文件:" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
ls -lsh >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
echo "开始查找错误日志文件内容;$(ls -t ./*)"  && \
echo "开始查找错误日志文件内容;$(ls -t ./*)" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
total_lines=$(cat * | wc -l) && \
# 控制打印10次进度日志
print_interval=$((total_lines / 10)) && \
output_file="$log_dir/lastDayErrorLog/error_analysis_result.log" && \
>> "$output_file" && \
echo "请确认以上文件信息,3秒后开始查找..." && \
sleep 3 && \
awk -v total_lines="$total_lines" -v print_interval="$print_interval" '
    BEGIN {
        context = 100; # 设置上下文为100行
        line_count = 0; # 记录当前处理的行数
        RED = "\033[38;5;196m"; # 红色
        BLUE = "\033[34m"; # 蓝色
        RESET = "\033[0m"; # 重置颜色
    }
    {
        # 跳过空白行
        if (NF == 0) {
            next;
        }

        # 打印提示信息
        if (line_count % print_interval == 0) {
            print "继续查找中... 当前行号:", NR, "/ 总行数:", total_lines;
        }
        line_count++;

        # 缓存所有行,不删除任何内容
        lines[NR] = $0;

        # 忽略不相关的行
        if ($0 ~ /uni_code_eventid_datatime_starttime_watereventhoursub|uni_monitorid_mn_code_starttime|海康云眸|无设备单元|登录失败|不包含|不合法|不匹配|存在|未在系统中|入参无效|没有【生效中】|找不到|重复|JwtToken|已过期|catalina|token 为空|被踢出|Broken pipe|ErrorPage|Servlet\.service$$ for servlet $dispatcherServlet$|无*数据/) {
            next;
        }

        # 缓存所有行,不删除任何内【应该提前,不然上下文不连续】
        # lines[NR] = $0;

        # 匹配目标关键字并记录命中行号
        if ($0 ~ /timeout|PSQLException: ERROR|ERROR|失败|EOFException|SocketException|IOException|sql执行出现异常|不判定为缺失/) {
            hit_lines[NR] = 1; # 记录命中行号
        }
    }
    END {
        # 将命中行号存储到数组中以便排序
        n = 0;
        for (hit_nr in hit_lines) {
            sorted_hits[++n] = hit_nr+0; # 强制转为数值
        }

        # 手动实现冒泡排序(适用于所有 awk 实现)
        for (i = 1; i <= n; i++) {
            for (j = i + 1; j <= n; j++) {
                if (sorted_hits[i] > sorted_hits[j]) {
                    temp = sorted_hits[i];
                    sorted_hits[i] = sorted_hits[j];
                    sorted_hits[j] = temp;
                }
            }
        }

        # 遍历排序后的命中行号,打印上下文
        last_nr = 0;
        err_idx = 0;
        for (i = 1; i <= n; i++) {
            hit_nr = sorted_hits[i];
            err_idx++;
            if(hit_nr < last_nr){
                continue;
            }

            printf("\n\n------------------------------------错误序号: %d-------------------------------------------\n", err_idx);
            printf("\n\n------------------------------------错误序号: %d-------------------------------------------\n", err_idx) >> "'"$output_file"'";

            # 打印命中行(红色高亮)
            printf("%s命中关键词: 命中行号 %d%s\n", RED, hit_nr, RESET);
            printf("%s%s%s\n", RED, lines[hit_nr], RESET); # 打印命中行,使用红色高亮

            # 写入文件:命中行
            printf("命中关键词: 命中行号 %d\n", hit_nr) >> "'"$output_file"'";
            printf("%s\n", lines[hit_nr]) >> "'"$output_file"'";

            # 打印下文
            at_counter = 0; # 统计连续以 "at" 开头的行数

            for (j = hit_nr + 1; j <= hit_nr + context; j++) {
                if (j in lines && length(lines[j]) > 0 && j >= 1) { # 确保 j 在有效范围内

                    at_counter++; # 增加计数器
                    last_nr = j;
                    # 已经超过5行,非 "at" 开头的行(at前面可能有多个空格,后面只有1个空格)
                    if (at_counter >= 5 && lines[j] !~ /^[[:space:]]*at /) {
                        printf("-----------------------后面无错误堆栈,只展示最近5条普通日志------------------------------\n", err_idx);
                        break; # 中止打印,到了堆栈的最后
                    }
                    if (lines[j] ~ /cn.jiangjiesheng|com.env|otherkeyword/) {
                        # 当前行包含指定关键词,打印蓝色
                        printf("%s[行号:%d] %s%s\n", BLUE, j, lines[j], RESET);
                        # 写入文件:关键词上下文
                        printf("[行号:%d] %s\n", j, lines[j]) >> "'"$output_file"'";
                    } else {
                        # 打印默认颜色
                        printf("[行号:%d] %s\n", j, lines[j]);
                        printf("[行号:%d] %s\n", j, lines[j]) >> "'"$output_file"'";
                    }
                }
            }
        }
    }
' unzip_file.log || true && \
echo " " && \
echo " " >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
echo "查找完成,准备删除解压文件" && \
echo "查找完成,准备删除解压文件" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
find "$log_dir/lastDayErrorLog" -maxdepth 1 -type f ! -name '*result*' -exec rm -f {} \; && \
echo "删除解压文件完成,执行ls -lsh结果" && \
echo "删除解压文件完成,执行ls -lsh结果" >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
ls -lsh && \
ls -lsh >> "$log_dir/lastDayErrorLog/error_analysis_result.log" && \
echo "是否下载分析结果文件 error_analysis_result.log? 输入 y 确认,其他键跳过【适用XShell,后期可以改成小文件不压缩】: " && \
read user_input && \
if [ "$user_input" = "y" ]; then
    tar -zcvf error_analysis_result.log.tar.gz error_analysis_result.log
    sz error_analysis_result.log.tar.gz || echo "文件下载失败,请检查环境是否支持 sz 命令。"
else
    echo "跳过文件下载。"
fi

2.3 【推荐】看我-在线脚本查询前1天业务报错gz压缩日志:

根据是否需要过滤相邻行的重复日志和只显示下文,选择上面的脚本内容

-- 先判断脚本是否存在
cd /home/logs/java-gz-log-dir && [ -f "analyze_logs.sh" ] && (echo "脚本已存在,直接执行..." && chmod +x analyze_logs.sh && ./analyze_logs.sh) || (echo "脚本不存在,开始下载..." && wget -O analyze_logs.sh --no-check-certificate --backups=0 https://tech.jiangjiesheng.cn/dev/shell/gn/analyze_logs.sh && chmod +x analyze_logs.sh && ./analyze_logs.sh)

-- 不判断脚本是否存在,存在就覆盖
cd /home/logs/java-gz-log-dir && wget -O analyze_logs.sh --no-check-certificate --backups=0 https://tech.jiangjiesheng.cn/dev/shell/gn/analyze_logs.sh && chmod +x analyze_logs.sh && ./analyze_logs.sh

2.4 效果展示

2.5 控制台终端打印的颜色

echo -e "\033[31m红色文字\033[0m"
echo -e "\033[91m亮红色文字\033[0m"
echo -e "\033[38;5;196m非常亮的红色文字\033[0m"

黑色:\033[30m
红色:\033[31m
亮红色文字:\033[91m
非常亮的红色文字:\033[38;5;196m
绿色:\033[32m
黄色:\033[33m
蓝色:\033[34m
紫色:\033[35m
青色:\033[36m
白色:\033[37m

2.6 其他环境快速参考说明

  • 压缩文件后缀名为.gz (非.tar.gz),如果不同:
    1、log_dir路径修改
    2、全局替换java-gz-log-dir,
    3、log_file修改: java-gz-log-dir-error.log.*.gz 也要改成具体的xxxx-error.log.*.tar.gz
    4、gunzip -c *.gz > unzip_file.log 替换成 tar -xvzf *.tar.gz -C unzip_file.log
    
  • windows编辑的sh脚本要执行去掉换行符:
    sed -i 's/\r$//' analyze_logs_*.sh
    
  • 注释#后一定要有空格。
正文到此结束
本文目录