ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux日志查询实战:高效过滤、时间截取与磁盘应急处理

Linux日志查询实战:高效过滤、时间截取与磁盘应急处理 做Linux运维和开发这么多年日志查询是每天都要干的事。但说实话大部分人的日志查询水平停留在grep error xxx.log这个阶段出了线上问题只能一行一行翻运气好几分钟定位运气不好折腾半小时。这篇博客不打算讲那些人人都知道的基础命令而是把我这些年实际用过、验证过的日志查询技巧整理一遍——从最基本的按关键词过滤到按时间段精确截取、多文件关联追踪再到慢查询日志统计以及日志挤爆磁盘怎么应急处理都会拆开讲清楚。不管你是在用tail -f盯着应用日志排查报错还是接到“某个接口响应很慢”的工单需要翻MySQL慢查询日志还是被研发追着要“traceId打印全链路日志”这篇文章都能给你一套直接能用的思路。内容偏实践命令我都实测过直接抄作业就行。1. 日志查询的整体思路先定位边界再动手查很多人一上来就grep整个大目录这是效率最低的方式。查询日志前应该先想清楚三件事查哪台机器、查哪个文件、查什么内容。这三件事想清楚命令怎么写基本就定了。1.1 日志文件落在哪里常见的日志路径与命名规则不同应用、不同部署方式的日志路径差别很大。常见的几类Java应用Spring Boot等一般通过logback或log4j2配置常见路径是/var/log/app/、/opt/app/logs/或者应用启动目录下的logs/。文件名常见app.log、app-info.log、app-error.log有的按天滚动叫app-2025-06-10.log按大小滚动叫app.log.1、app.log.2。Nginx日志通常由nginx.conf的access_log和error_log指令控制。路径常见/var/log/nginx/access.log、/var/log/nginx/error.log按天切割后会有access.log-20250610这种带日期的文件。MySQL慢查询日志由my.cnf里的slow_query_log_file指定常见/var/log/mysql/mysql-slow.log或/var/lib/mysql/目录下。系统日志/var/log/messagesCentOS系、/var/log/syslogUbuntu/Debian系还有/var/log/dmesg看内核启动信息。Docker容器日志用docker logs 容器名日志文件在宿主机的/var/lib/docker/containers/容器ID/容器ID-json.log。我的习惯是接到需求先ls -lt看目录下最新的日志文件是哪个。因为日志轮转logrotate经常会生成带时间戳或数字后缀的文件如果只看固定的app.log可能根本没查到报错因为报错已经在滚动后的app.log.1里了。1.2 查询前的三个关键确认时间、级别、关键字具体开查之前建议先在脑子里过一遍时间区间报错或者异常发生在几点几分这个决定你是tail看最近内容还是用sed截取某个时间段的内容还是zcat去翻历史压缩包。日志级别是ERROR、WARN还是DEBUG对应到日志文件可能是不同的文件很多应用会把 error 单独输出到一个文件或者是同文件内不同level的混合记录。搜索关键字最可能出现的报错关键词或业务唯一标识。比如NullPointerException、timeout、connection refused或者更精准的订单号、用户ID、traceId。注意日志查询最容易踩的坑是“关键字记忆错误”。比如报错文本实际是Error而你在grep时用了error区分大小写结果什么都查不到。稳妥做法是先用一个模糊的小写关键词试探或者干脆用grep -i忽略大小写。2. 高频日志查询命令实战从过滤到截取一次性到位这一节是全文的核心每个命令我都标注了适用场景。建议你把这些命令存成一个shell脚本或者做成别名平时线上排查能省很多时间。2.1 grep 与 egrep按关键词过滤日志的最强组合基础用法grep 关键词 app.log我就不多说了说几个容易被人忽略的点。grep -i忽略大小写适合你不确定日志里是error还是Error的场合。grep -n打印行号这个在Vim查看时定位特别有用也方便用sed -n二次截取。grep -C 5上下文各5行和grep -A 5/grep -B 5后5行/前5行是我实际排查异常时最常用的参数——异常堆栈从来不是一行只grep Exception只能看到第一行后面的具体报错过程全靠-A带出来。多个关键词组合过滤用扩展正则表达式。比如同时匹配timeout或timed outgrep -iE timeout|timed out app.log | tail -50排除干扰关键词用grep -v。比如你不想看心跳日志heartbeat只想看真正的业务报错grep -iE error|exception app.log | grep -v heartbeat | tail -100这个管道叠加的思路是日志排查的基础记住一个原则先用宽泛关键词圈范围再用排除词缩小范围。2.2 按时间段截取日志sed 与 awk 的时间区间定位线上排查最常见的需求就是“上午10:00到10:30之间发生了什么”。如果你只是用grep去搜会搜出所有时间点出现相同关键词的记录干扰巨大。这时候应该先按时间段把日志切出来。假设日志的每一行开头是2025-06-10 10:15:30.123用sed配合正则做范围匹配sed -n /2025-06-10 10:00:00/,/2025-06-10 10:30:00/p app.log这条命令会把10:00:00到10:30:00之间的所有行都输出。注意边界问题如果你的精确时间点在日志里不存在比如10:00:00.000那行因为并发写入被推迟到了10:00:00.235sed的起始匹配就不生效。我的技巧是用一个略早的时间点做起点比如用10:00:00会漏那就用10:00去匹配再用head或awk进一步处理。另一个更稳定的做法是用awk按时间字符串比较awk $0 2025-06-10 10:00:00 $0 2025-06-10 10:30:00 app.log前提是日志行首的时间格式统一且是按字节流顺序写入的绝大多数应用日志满足这个条件。awk的做法在日志时间跨分钟、跨小时不均匀时尤其稳定不会因为边界行缺失而匹配失败。2.3 tail、head、less 组合实时跟踪与快速预览线上监控最常用的还是tail。tail -f app.log是持续跟踪文件尾部新写入的内容适合观察实时输出如果只想看最近100行用tail -100如果文件太大直接tail -f会对磁盘IO有压力建议配合--pid参数在进程退出时自动结束tail -f --pid$!写进脚本时常用。head用得少但有个场景很有用日志文件刚切割完想看新文件的前几行确认格式head -20 app.log一眼看清时间格式和字段结构方便后面写awk表达式。less是日志查询里的隐藏神器。不要只用tail翻完就结束less app.log打开大文件几乎秒开支持 Vi 风格快捷键在文件里用/error向下搜索、?error向上搜索翻页用PgUp/PgDn跳到最后用G回到开头用gg。配合-N显示行号查找后按n跳到下一处匹配体验接近用Vim刷日志但打开大文件比Vim快得多。2.4 日志统计与按字段聚合sort、uniq、awk 的正确用法有时候我们要的不是某一条日志而是想从日志里看出趋势——某个IP访问了多少次、某个接口报错了多少次、某个用户产生了多少条异常记录。这时候就要用到统计命令组合拳。统计ERROR日志里每行出现的次数并排序grep ERROR app.log | sort | uniq -c | sort -rn这条命令先grep过滤再sort把相同行聚在一起uniq -c统计每个相同行的数量最后的sort -rn按数量从大到小排列。它会输出报错信息和对应的次数马上就能看出哪个报错是最严重的。不过sort | uniq -c有个前提相同的行必须相邻所以sort不能省。用awk按某个字段聚合更高级。比如access.log里通常第1列是客户端IP想统计每个IP的访问次数awk {count[$1]} END {for (ip in count) print count[ip], ip} access.log | sort -rn | head -20这个awk脚本先建了一个叫count的关联数组键是第一个字段IP值是该IP出现的次数。所有行处理完后END遍历数组打印次数和IP再交给sort -rn取前20个。同理如果想统计哪个接口返回了最多的5xx可以用类似逻辑按第七列URL或第八列状态码聚合。3. 场景进阶多文件检索、traceId链路追踪与慢查询日志分析基础命令用熟练了接下来就是实际场景的综合演练。这几个场景我挑的是线上最常遇到的日志分散在多个文件、一次请求跨多个模块需要串联、接口变慢需要查MySQL慢查询。3.1 多文件同时检索find grep xargs 的组合套路生产环境每个模块一个日志目录报错只告诉你“支付服务有问题”但支付服务在A机器还是B机器、今天切到哪个目录了都得靠查。不想一台台登录、一个个文件去看可以先用find列出符合条件的最新文件find /data/logs -name *.log -mmin -60这条会列出60分钟内被修改过的所有.log文件——如果日志按天滚动大部分情况下你只需要看最新的那个。然后针对这些文件做批量检索find /data/logs -name *.log -mmin -60 | xargs grep -l 出错了grep -l只输出“包含该关键词的文件名”能快速定位报错到底落在哪个文件。定位到具体文件后再对该文件做精细化查询。如果想一次在所有日志文件里搜关键词并显示文件名和行号grep -rn NullPointerException /data/logs/ --include*.log --include*.out-r表示递归扫描/data/logs/目录下所有文件--include限定文件后缀。这里要警惕大文件递归扫描的压力在日志文件较多的目录慎用否则可能把CPU跑满。3.2 基于traceId的全链路日志串联一次请求多个日志文件的追踪方法微服务架构下一次请求会经过网关、订单服务、支付服务、MQ消费者等多个节点。每跳一个服务日志文件就换一个。如果每个服务都打印了traceId你可以以这个Id作为主线把散落的日志“串起来”。假设某次报错的traceId是6aa2526590ad07346b76e2b8d8d80384先在第一个服务里查grep -n 6aa2526590ad07346b76e2b8d8d80384 /data/logs/order/app.log拿到这个服务打印出的下一跳信息比如它调用了支付服务、传出的下游traceId再到支付服务目录里查同一个traceIdgrep -n 6aa2526590ad07346b76e2b8d8d80384 /data/logs/pay/*.log这时候可以用-C 10看上下文把异常发生前后的业务细节都带出来。我在实际排查中常在多个终端窗口分别跑这几个grep一边看一边对照时间戳能很快定位是哪一环超时、哪一环抛异常。一个非常重要的经验好记性不如烂笔头。每次排查问题都建议把traceId、命令、日志文件路径、初步判断整理到一个临时笔记里。别嫌麻烦很多线上问题的根因是“多个请求之间的traceId被日志框架截断或打印成null”这时你要顺着时间戳 上下游调用关系去找。如果服务没有全链路traceId只能退而求其次用“用户ID 时间区间”作为关联键去各服务日志里交叉检索。另一个参考做法是日志采集到 Elasticsearch 后用traceId检索。很多团队会在日志采集配置里把traceId映射为 ES 的一个字段这样就不用登机器grep了。但底层逻辑一样找一个全局唯一的关联键把分散的日志串成一条线。3.3 MySQL慢查询日志统计分析与可视化看板的底层逻辑热搜词里有一条“mysql慢查询日志统计分析与可视化看板”这个方向我做过几次说说实用做法。先用MySQL原生功能确认慢查询是否开启SHOW VARIABLES LIKE slow_query_log%;如果没开需要改配置并重启MySQL或者在当前会话临时开启SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 2;long_query_time的单位是秒2表示超过2秒的SQL才会被记录。慢查询日志默认是文本格式一行是SQL的一句描述。统计最常见的慢SQL可以先用mysqldumpslow工具mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log-s t表示按查询时间排序-t 10取前10条。它会自动把SQL里的具体数字和字符串替换成N和S把“长得像”的SQL聚合在一起这样统计出来的才是“真实的有问题的SQL模式”而不是被具体参数拆得七零八落。想看更详细的每次执行时间和扫描行数直接文本分析mysqldumpslow -s al -t 20 /var/log/mysql/mysql-slow.log这里-s al是按平均锁时间排序能找出“锁等待严重”的SQL。如果要可视化可以把慢查询日志解析成 CSV 后导入 Grafana、Quick BI 或自研的看板。解析的方法很简单就是awk按行匹配# Time:、# UserHost:、# Query_time:这些字段重新格式化awk /# Query_time/{print $3, $NF} /var/log/mysql/mysql-slow.log | sort -rn | head -20这行命令提取出每条慢查询的执行时间和最后一行关键字通常是SQL语句或部分语句排序后取前20条就能快速定位“最拖后腿的SQL”。注意慢查询日志格式在不同MySQL版本里有差异。MySQL 5.7和8.0的慢查询日志头字段基本一致但 8.0 默认会用更详细的服务端信息建议先head -20看一眼格式再写解析脚本。4. 日志查询的进阶治理大文件处理、空间释放与问题排查速查日志查询的技术除了“怎么查”还包括“查的时候遇到的各种环境问题”——最典型的是日志文件大到几GB打不开、日志把磁盘写满导致服务挂掉、删除日志文件后空间不释放。这些问题不定时来一次遇上了就要立刻处理。4.1 超大日志文件的读取策略less、zcat、split 的组合用法日志文件超过1GB甚至10GB时vim直接打不开cat会把终端刷爆。这时候你要学会“分段读”。less是最友好的选择因为它是按需读取文件块不会把整个文件加载进内存1GB 的日志也能秒开。操作方式和前面说的一样/关键词搜索G跳末尾gg跳到开头。如果是滚动压缩过的文件用zcat查看zcat app.log.20250610.tar.gzzcat会把.gz压缩文件解压后输出到标准输出可以直接接管道过滤。比如查压缩日志中的报错zcat app.log.20250610.tar.gz | grep ERROR | head -50如果压缩包内文件很多且彼此独立更推荐zgrepzgrep ERROR app.log.20250610.tar.gz它相当于grep的压缩版不用解压整个文件就能检索适合多文件快速定位。还有一种场景日志文件太大想按行数切分方便携带或交给别的工具分析split -l 50000 app.log part_这条命令会把app.log按每5万行切成多个文件生成part_aa、part_ab……然后用grep分别查。我一般只在本地分析时用线上不建议对正在写入的日志做split因为切割期间文件仍在增长结果不可控。4.2 日志挤爆磁盘的应急处理du、lsof以及WSL删除文件后空间不释放问题热搜词有一条“wsl linux删除文件后空间没释放”这个问题在传统Linux服务器上也会出现你明明rm删了文件df -h一看磁盘占用率还是100%。原因是某个进程仍持有该文件的文件句柄文件在文件系统里虽然被“删除”了但进程还在写或读占用的空间要等进程关闭文件句柄才会真正释放。排查步骤df -h先看哪个分区满了。然后lsof | grep deletedlsof列出所有打开的文件grep deleted直接过滤出“已删除但仍有进程占用的文件”。找到占用文件的进程名和PID后重启该进程或让应用重新加载日志文件空间才会释放。如果是WSLWindows Subsystem for Linux场景除了lsof外还可能是VHD虚拟磁盘文件没有自动压缩。WSL的整个文件系统都存放在Windows下的一个虚拟磁盘.vhdx里你在WSL内删除文件磁盘里虽然腾出了可用块但.vhdx文件本身不会自动变小。需要手动压缩wsl --shutdown # PowerShell里执行 Optimize-VHD -Path C:\Users\你的用户名\AppData\Local\Packages\...\ext4.vhdx -Mode FullOptimize-VHD是Windows自带的Hyper-V模块命令需要管理员权限。压缩前必须确保WSL完全关闭否则会报错。这个经验我踩过坑分享出来特别提醒WSL删文件后空间不释放先查lsof确认没有进程占用后再执行VHD优化顺序不能反。4.3 日志查询常见问题排查速查表日志查询会遇到的坑很多我整理了一张速查表都是实际工作中验证过的现象可能原因排查方法grep 搜不到关键词但日志里明明有关键词大小写不匹配或日志在滚动后的旧文件里用grep -i用ls -lt查看最新滚动文件tail -f 不输出内容文件在滚动切割tail 跟踪的是旧的 inode用tail -F大写F自动跟踪文件重新创建awk 时间区间截取为空时间边界处没有精确匹配行起止时间稍微放宽或用比较而非精确匹配日志报错太多不知道重点只看了报错行没看堆栈上下文用grep -A 20把堆栈一次性带出日志里有乱码或中文显示异常文件编码不是UTF-8用file app.log查编码用iconv -f GBK -t UTF-8转换磁盘满了但找不到大文件大文件被删除但进程占用或日志文件在别的挂载点lsof | grep deleteddf -h确认分区再定位查询历史压缩日志找不到入口.tar.gz或.gz文件不能直接 grep用zgrep或zcat检索访问日志按IP统计不准中间有代理或负载均衡真实IP在X-Forwarded-For头调整 awk 或 grep 的字段位置取代理头里的IP这张表不是死的不同团队、不同应用的日志格式差异很大但排查思路是一致的先看格式、再看时间、最后精确定位。4.4 把“查日志”做成日常习惯别名、脚本和轮转策略日志查询不只用于排查故障还可以做成日常巡检。我常用两个技巧第一个是给高频命令做别名。在~/.bashrc或~/.zshrc里加上alias errgrepgrep -iE error|exception alias logtailtail -f -n 100 alias slowlogmysqldumpslow -s t -t 10这样平时敲命令能省几秒连续排查时效率提升很明显。第二个是把日志轮转配好。日志文件只涨不删再大的磁盘也会满。Linux 自带的logrotate是最省事的轮转工具。在/etc/logrotate.d/下创建应用对应的配置/data/logs/app/*.log { daily rotate 7 compress delaycompress missingok notifempty sharedscripts postrotate /bin/kill -USR1 cat /var/run/app.pid endscript }这段配置的含义是每天轮转一次保留7份历史日志历史日志压缩为.gz轮转后主动给应用进程发USR1信号让它重新打开日志文件。delaycompress表示轮转后第一份不立即压缩因为下一条日志可能还在写。日志轮转配好后查日志时看到-YYYYMMDD.gz后缀的旧文件基本上可以放心判断它不会再增长也能安心用zgrep去查。5. 个人经验与建议日志查询的本质是“快速定位问题”而不是“背命令”我遇到过很多同事把日志查询当成“背命令”的活觉得会grep、tail、awk就够用了。实际用下来真正拉开差距的是你有没有“日志思维”——日志只是系统在关键时刻留下的脚印你的任务是顺着脚印推断当时发生了什么。我的建议是先练熟最常用的5个组合grep -A/-B看上下文、sed/awk按时间截取、tail -F实时跟踪滚动文件、sort uniq -c做频率统计、find xargs grep做跨文件检索。这5个组合覆盖了我日常80%的排查场景。再往深走可以去研究jq处理JSON格式日志、lnav做日志文件交互式浏览、grok规则做日志字段提取这些工具能在特定场景里把效率再拉高一个档次。最后再分享一个实操细节查日志时时间戳格式一定要确认清楚。有的应用打印的是2025-06-10 10:00:00有的只有10:00:00还有的是Unix时间戳毫秒级13位。如果拿带日期的字符串去awk比较而日志只有时分秒必然匹配不上。遇到Unix时间戳先换算成可读时间再写过滤条件或者直接用date -d 1720000000做转换。这个小细节看着不起眼实际排查中能卡掉一大半人。
返回列表