lnav —— 终端里的日志分析器
lnav —— 终端里的日志分析器
分类:09 日志与监控 适用:Linux / macOS(lnav 0.10 ~ 0.12) 一句话:自动识别日志格式、多文件按时间合并、支持 SQL 查询,比
tail/grep强一个维度。
1. 它解决什么问题
- 一次故障涉及 5 个服务的日志,时间线对不上。
- 要在几百万行里找出"某个时间点前后发生了什么"。
- 想对日志做统计(按状态码分组、按分钟计数),但不想写脚本。
- JSON 日志混着文本日志,
grep很难看。
2. 安装
apt install -y lnav
dnf install -y lnav
apk add lnav
# macOS
brew install lnav
3. 基础用法
lnav /var/log/nginx/access.log
lnav /var/log/nginx/*.log # 多文件合并
lnav -t /var/log/*.log # 从 stdin/管道读
tail -f app.log | lnav
lnav -r /tmp/crash.log # 只读打开
打开后界面分三块:上方日志区、中间命令行(按 :)、下方状态栏(当前时间、过滤条件)。
自动识别格式
lnav 内置上百种格式(nginx、apache、syslog、JSON、Java 堆栈、K8s 等)。识别失败时可以手动指定:
lnav -i /path/to/custom.json # 安装自定义格式
4. 导航与搜索
| 按键 | 作用 |
|---|---|
/ |
向下搜索(正则) |
? |
向上搜索 |
n / N |
下一个 / 上一个匹配 |
g / G |
跳到开头 / 结尾 |
Ctrl-] |
跳到下一个"错误"(内置错误识别) |
e / E |
下一个 / 上一个 error |
w / W |
下一个 / 上一个 warning |
Tab |
在文件/时间/错误之间循环跳转 |
Space |
下一页 |
b |
上一页 |
q |
退出(再按确认) |
时间跳转(核心优势)
:goto 2026-11-05 14:30:00
跳到指定时间点,多文件会自动对齐。也可以 Shift+G 后输入时间。
5. 过滤
:filter-in error
:filter-in 'timeout|refused' # 正则
:filter-out healthcheck
:filter-out 'DEBUG|TRACE'
:reset-filters # 清除所有过滤
过滤是"视图级"的,不修改文件,可叠加多个条件。状态栏会显示当前生效的过滤数。
6. SQL 查询(最强功能)
按 ; 进入 SQL 模式(或 :Q),日志被当成表 log_line:
;SELECT count(*) FROM log_line
;SELECT count(*) FROM log_line GROUP BY log_level
;SELECT log_body FROM log_line WHERE log_body LIKE '%timeout%' LIMIT 20
常用字段
| 字段 | 含义 |
|---|---|
log_line |
行号 |
log_time |
时间戳 |
log_body |
正文 |
log_level |
级别(error/warning/info) |
log_mark |
是否被标记 |
log_comment |
注释 |
log_format |
识别到的格式 |
按分钟统计
;SELECT strftime('%Y-%m-%d %H:%M', log_time) AS minute, count(*)
FROM log_line GROUP BY minute ORDER BY minute DESC LIMIT 30
找耗时最长的请求(nginx)
;SELECT log_body FROM log_line
WHERE log_body LIKE '% 5__ %' LIMIT 50
lnav 自动解析 nginx 的字段后,还可以用 $ 变量:
;SELECT count(*) FROM access_log GROUP BY sc_status
不同版本对 nginx 的字段提取命名不同(
sc_status、cs_uri_stem),用:show或;PRAGMA table_info(access_log)查看。
结果导出
;SELECT ... INTO OUTFILE '/tmp/result.csv'
7. 可视化
| 按键 | 作用 |
|---|---|
i |
直方图(按时间分布,找尖峰) |
p |
时序图(数值字段趋势) |
v |
在直方图中切换粒度 |
x |
切换直方图过滤(选中区间只看该时段) |
直方图是按 log_time 聚合的行数,故障时能一眼看出"从哪个时间点开始爆"。
8. 标记与注释
| 按键 | 作用 |
|---|---|
m |
标记当前行 |
M |
清除标记 |
c |
添加注释 |
Shift+C |
清除所有注释 |
u / U |
下一个 / 上一个标记 |
标记行可用于"记录关键证据",退出前可以导出。
9. 常用命令行参数
lnav -c ':goto 14:30' app.log # 打开后直接执行命令
lnav -c ';SELECT count(*) FROM log_line' app.log
lnav -n # 不加载用户配置
lnav -C # 不加载任何配置(排障用)
lnav -d /tmp/lnav-debug.log # 调试
lnav -f # 跟随模式(类似 tail -f)
10. 实战场景
10.1 多服务日志对齐时间线
lnav /var/log/nginx/error.log /var/log/app/*.log /var/log/mysql/error.log
# 按 Tab 在文件间跳,按 i 看整体分布,:goto 到故障时间点
lnav 会把不同格式的日志按时间戳排序展示,这是它相对 cat 的最大价值。
10.2 快速定位错误上下文
lnav app.log
# 按 e 跳到下一个 error,Ctrl-] 跳到下一个异常堆栈
# 按 / 搜索 request_id,看同一请求的所有日志
10.3 统计 5xx
lnav access.log
;SELECT count(*) FROM access_log WHERE sc_status >= 500
10.4 从线上拉日志本地分析
ssh prod 'cat /var/log/app/*.log' | lnav -t
不落地,直接分析,适合临时排障。
10.5 编写自定义格式(自研日志)
~/.lnav/formats/mylog.json:
{
"mylog": {
"title": "My App Log",
"json": true,
"regex": {
"std": {
"pattern": "^(?<timestamp>\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}) \\[(?<level>\\w+)\\] (?<body>.*)$"
}
},
"level-field": "level",
"value": { "timestamp": { "kind": "timestamp", "format": "%Y-%m-%d %H:%M:%S" } }
}
}
lnav -i ~/.lnav/formats/mylog.json app.log
11. 常见坑
- 时间识别失败:日志没有统一时间格式,
log_time为空,排序错乱。写自定义格式。 - 超大文件:几百 MB 可以,几 GB 会慢,先
gzip后用zcat | lnav -t。 - 多文件时间跨度大:lnav 按时间对齐,若某文件时间戳异常会导致视图跳跃。
;是 SQL 模式:在搜索里想匹配分号要转义。- SQL 只读当前视图:过滤后的行不影响 SQL 全量,注意区分。
- 退出要按两次
q:第一次提示确认,防止误退。 - 颜色在管道里失效:
lnav -t输出纯文本。 - 自定义格式路径:
~/.lnav/formats/下需要manifest.json或直接放 json 文件。 - 远程 SSH 里中文乱码:终端 locale 问题,与 lnav 无关。
- 不替代集中日志平台:单机临时排障可以,长期检索还是要 ELK/Loki。
12. 速查表
lnav file.log
lnav /var/log/*.log
tail -f app.log | lnav
lnav -t < file.log
/ ? n N 搜索
e E w W 跳错误/警告
i 直方图
p 时序图
m / c 标记 / 注释
Tab 文件/时间/错误跳转
:goto 14:30 跳时间
:filter-in error / :filter-out debug / :reset-filters
;SELECT ... FROM log_line
:quit