在线上定位1G日志文件中的异常信息时,我这样做合适吗

1G级线上日志文件 的异常定位系统性方案

一、快速定位流程

python 复制代码
import datetime
import random

def generate_springboot_log(file_name, file_size_gb):
    # 模拟Spring Boot日志内容
    log_levels = ["INFO", "DEBUG", "WARNING", "ERROR"]
    classes = ["com.example.controller.HomeController", "com.example.service.UserService", 
               "com.example.repository.UserRepository", "com.example.config.WebConfig"]
    messages = [
        "Accessing /home endpoint",
        "User not found with id: {}",
        "Invalid request parameters",
        "Database connection established",
        "Starting application",
        "Shutting down application"
    ]

    # 计算需要写入的行数
    file_size_bytes = file_size_gb * 1024 ** 3
    # 首先生成一条样本日志行,计算其长度
    sample_log = f"[2023-10-01 12:34:56.789] {random.choice(classes)} - {random.choice(log_levels)} : {random.choice(messages)}"
    average_line_length = len(sample_log) + 1  # 加1是因为每行最后还有一个换行符

    with open(file_name, "w", encoding="utf-8") as f:
        # 计算需要写入的行数
        lines_needed = int(file_size_bytes // average_line_length) + 1
        for _ in range(lines_needed):
            timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]  # 保留毫秒
            log_level = random.choice(log_levels)
            clazz = random.choice(classes)
            message = random.choice(messages)
            # 如果日志消息中包含格式化的参数,添加示例数值
            if "{}" in message:
                message = message.format(random.randint(1, 100))
            log_line = f"[{timestamp}] {clazz} - {log_level} : {message}\n"
            f.write(log_line)

generate_springboot_log("springboot_log_1gb.log", 1)

思路:利用时间过滤数据,再利用管道流过滤输出到单独的文件,最后在小文件里面操作就行。

shell 复制代码
[2025-03-16 21:14:11.476] com.example.repository.UserRepository - INFO : Starting application
[2025-03-16 21:14:11.476] com.example.service.UserService - WARNING : User not found with id: 76
[2025-03-16 21:14:11.476] com.example.service.UserService - INFO : Shutting down application
[2025-03-16 21:14:11.476] com.example.service.UserService - ERROR : Starting application
[2025-03-16 21:14:11.476] com.example.config.WebConfig - INFO : User not found with id: 83
[2025-03-16 21:14:11.476] com.example.service.UserService - WARNING : Accessing /home endpoint
[2025-03-16 21:14:11.476] com.example.repository.UserRepository - ERROR : Accessing /home endpoint
[2025-03-16 21:14:11.476] com.example.config.WebConfig - INFO : User not found with id: 57
[2025-03-16 21:14:11.476] com.example.repository.UserRepository - INFO : User not found with id: 89
[2025-03-16 21:14:11.476] com.example.controller.HomeController - ERROR : Database connection established
[2025-03-16 21:14:11.476] com.example.config.WebConfig - ERROR : Accessing /home endpoint
[2025-03-16 21:14:11.476] com.example.controller.HomeController - INFO : Shutting down application
[2025-03-16 21:14:11.476] com.example.repository.UserRepository - INFO : Database connection established
[2025-03-16 21:14:11.476] com.example.config.WebConfig - DEBUG : User not found with id: 16
[2025-03-16 21:14:11.476] com.example.controller.HomeController - WARNING : Database connection established
[2025-03-16 21:14:11.476] com.example.controller.HomeController - ERROR : Accessing /home endpoint
[2025-03-16 21:14:11.476] com.example.controller.HomeController - WARNING : Invalid request parameters
[2025-03-16 21:14:11.476] com.example.repository.UserRepository - WARNING : Invalid request parameters
[2025-03-16 21:14:11.476] com.example.controller.HomeController - WARNING : Accessing /home endpoint
[2025-03-16 21:14:11.476] com.example.service.UserService - DEBUG : Starting application
[2025-03-16 21:14:11.476] com.example.config.WebConfig - ERROR : Starting application
[2025-03-16 21:14:11.476] com.example.config.WebConfig - WARNING : User not found with id: 42
shell 复制代码
awk -v start="[2025-03-16 21:14:11.476]" -v end="[2025-03-16 21:14:11.477]" '($0) >= start && ($0) < end {print}' springboot_log_1gb.log | grep 'ERROR' -> test.log
html 复制代码
($0) >= start && ($0) < end {print}:对每一行内容 $0 进行比较。如果当前行的时间在 start 和 end 之间(包含等于的情况),则打印该行,(测试($0) <= end {print}得到的结果不包括等于)

二、高效处理大文件的技巧

分割和并行处理 : 使用<font style="color:rgb(37, 43, 58);">split</font>将日志文件分割为小文件,分别处理,再合并结果。

shell 复制代码
split -l 100000 springboot_log_1gb.log chunk_

-l 100000:每个小文件包含1000行。

chunk_ :前缀,生成 chunk_aa、chunk_ab 等文件。

shell 复制代码
rm -rf chunk_*
shell 复制代码
split -b 200M --verbose springboot_log_1gb.log split_access_


-b 200M:每个分片200MB
--verbose:显示分割进度
输出文件命名示例:split_access_aa,split_access_ab
shell 复制代码
split -l 5000 -d --additional-suffix=.log springboot_log_1gb.log "split_$(date +%Y%m%d)_"

-additional-suffix:添加文件扩展名
$(date +%Y%m%d):动态生成日期前缀

split_20250316_991230.log

超大文件分块处理:

shell 复制代码
split -l 100000 app.log chunk_  # 每10万行切割文件
find . -name "chunk_*" | xargs -P 4 grep "ERROR" >> errors.txt

优势:避免单文件内存溢出问题
html 复制代码
find . -name "chunk_*":查找当前目录(.)及其子目录中所有文件名以 "chunk_" 开头的文件。
* 是通配符,表示任意字符序列。

xargs -P 4:使用 xargs 将输入的文件名作为参数传递给后续命令。-P 4 表示同时运行 4 个进程,提高处理速度。

grep "ERROR":在每个文件中搜索包含 "ERROR" 的行。grep 是一个强大的文本搜索工具,支持正则表达式。

>> errors.txt:将 grep 找到的所有包含 "ERROR" 的行追加到 errors.txt 文件中。
如果 errors.txt 不存在,会创建一个新文件。
shell 复制代码
find . -name "chunk_*" | xargs rm


动态追加写入:

shell 复制代码
tail -f app.log | grep --line-buffered "ERROR" | xargs -I{} sh -c 'echo {} >> errors.txt'

-line-buffered:强制逐行输出缓冲

xargs:将标准输入转换为命令行参数。
-I{}:指定{}作为每行输入的占位符。
sh -c:执行一个命令。
echo {} >> errors.txt:将每一行ERROR日志追加到errors.txt文件中。


避免内存问题:

shell 复制代码
grep "ERROR" logfile.log | awk '{print $0}'  # 避免 `cat logfile.log | ...`
方法 10GB日志耗时 CPU占用 内存峰值
原生grep 22分钟 98% 1.8GB
xargs单线程 19分钟 25% 800MB
xargs并行(-P 8) 4分30秒 620% 2.1GB

指标来源于网络,仅供参考

三、实时监控与自动化

shell 复制代码
tail -f /path/to/logfile.log | grep "ERROR"  # 实时显示新增的ERROR日志

异常复现的时候可以使用
shell 复制代码
tail -f logfile.log | awk '/ERROR/ {print strftime("%Y-%m-%d %H:%M:%S"), $0}'  # 添加时间戳
相关推荐
BillKu1 小时前
Java + Spring Boot + Mybatis 实现批量插入
java·spring boot·mybatis
YuTaoShao1 小时前
Java八股文——集合「Map篇」
java
IT成长日记2 小时前
05【Linux经典命令】Linux 用户管理全面指南:从基础到高级操作
linux·运维·服务器·用户管理·命令
emo了小猫2 小时前
Mybatis #{} 和 ${}区别,使用场景,LIKE模糊查询避免SQL注入
数据库·sql·mysql·mybatis
有梦想的攻城狮3 小时前
maven中的maven-antrun-plugin插件详解
java·maven·插件·antrun
小鱼小鱼.oO5 小时前
阿里云服务器安装nginx并配置前端资源路径(前后端部署到一台服务器并成功访问)
服务器·nginx·阿里云
硅的褶皱7 小时前
对比分析LinkedBlockingQueue和SynchronousQueue
java·并发编程
MoFe17 小时前
【.net core】天地图坐标转换为高德地图坐标(WGS84 坐标转 GCJ02 坐标)
java·前端·.netcore
潘yi.7 小时前
NoSQL之Redis配置与优化
数据库·redis·nosql
zdkdchao7 小时前
hbase资源和数据权限控制
大数据·数据库·hbase