在线上定位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}'  # 添加时间戳
相关推荐
liujing102329298 分钟前
Day04_刷题niuke20250703
java·开发语言·算法
阿巴~阿巴~9 分钟前
Linux基本命令篇 —— alias命令
linux·服务器·bash
Brookty10 分钟前
【MySQL】JDBC编程
java·数据库·后端·学习·mysql·jdbc
能工智人小辰24 分钟前
二刷 苍穹外卖day10(含bug修改)
java·开发语言
DKPT25 分钟前
Java设计模式之结构型模式(外观模式)介绍与说明
java·开发语言·笔记·学习·设计模式
缘来是庄27 分钟前
设计模式之外观模式
java·设计模式·外观模式
先做个垃圾出来………1 小时前
SQL的底层逻辑解析
数据库·sql
好名字更能让你们记住我1 小时前
Linux多线程(十二)之【生产者消费者模型】
linux·运维·服务器·jvm·windows·centos
码不停蹄的玄黓1 小时前
深入拆解MySQL InnoDB可重复读(RR)隔离级别:MVCC+临键锁如何「锁」住一致性?
数据库·mysql·可重复读
门思科技1 小时前
设计可靠 LoRaWAN 设备时需要考虑的关键能力
运维·服务器·网络·嵌入式硬件·物联网