lnav —— 终端里的日志分析器

运维工具手册 09-日志与监控 4.7 KB 原文

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. 常见坑

  1. 时间识别失败:日志没有统一时间格式,log_time 为空,排序错乱。写自定义格式。
  2. 超大文件:几百 MB 可以,几 GB 会慢,先 gzip 后用 zcat | lnav -t。
  3. 多文件时间跨度大:lnav 按时间对齐,若某文件时间戳异常会导致视图跳跃。
  4. ; 是 SQL 模式:在搜索里想匹配分号要转义。
  5. SQL 只读当前视图:过滤后的行不影响 SQL 全量,注意区分。
  6. 退出要按两次 q:第一次提示确认,防止误退。
  7. 颜色在管道里失效:lnav -t 输出纯文本。
  8. 自定义格式路径:~/.lnav/formats/ 下需要 manifest.json 或直接放 json 文件。
  9. 远程 SSH 里中文乱码:终端 locale 问题,与 lnav 无关。
  10. 不替代集中日志平台:单机临时排障可以,长期检索还是要 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
lnav —— 终端里的日志分析器 - 知识库 - 起航社区