在线上定位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}'  # 添加时间戳
相关推荐
yexuhgu1 小时前
如何为禁用按钮点击添加提示文案
jvm·数据库·python
duke8692672141 小时前
JavaScript数组扁平化flat与flatMap处理嵌套数据
jvm·数据库·python
夏沫琅琊1 小时前
Mac 上用 Homebrew 安装 DB Browser for SQLite 时,被 Homebrew 自动更新卡住了
数据库·macos·sqlite
ch.ju1 小时前
Java Programming Chapter 3——Subscript of the array
java·开发语言
m0_740796361 小时前
mysql如何通过脚本自动化创建用户_使用shell配合mysql命令
jvm·数据库·python
会编程的土豆1 小时前
Gin 框架第一课:从 0 搞懂 Gin 最基础的路由
数据库·sql·gin·goland
雨浓YN1 小时前
GKTGD 工业监控系统-02MySQL 数据库技术文档(类库:NET8_SQLData)
数据库·wpf
雨落在了我的手上1 小时前
初识java(三):运算符
java·开发语言
山人在山上1 小时前
arcgis server 暴力迁移
运维·服务器·arcgis
dFObBIMmai1 小时前
JavaScript中对象生命周期与垃圾回收的引用关系
jvm·数据库·python