GoAccess 常用 CLI 命令与工具详解
GoAccess 命令行完全指南:终端 TUI、HTML、JSON、CSV 四种输出形态的命令矩阵与实测回显,实时大屏、多日志合并、gzip 压缩日志、小时粒度、persist/restore 增量分析与 systemd timer 定时报告方案。
GoAccess 常用 CLI 命令与工具详解
> 目标:把 GoAccess 的日常命令一次讲全——四种输出形态的命令矩阵、实时大屏、多日志合并、压缩日志、时间粒度切换、增量分析与定时报告,每条命令均附 Ubuntu 22.04 上的真实执行回显,可直接照抄到生产脚本。
一、环境信息
本文所有命令在以下环境实测:
- 操作系统:Ubuntu 22.04.4 LTS(x86_64),内核 6.8.0-138-generic
- GoAccess 1.9.4(
/usr/local/bin/goaccess,编译参数--enable-utf8 --enable-geoip=mmdb) - GeoIP 库:GeoLite2-Country.mmdb(位于
/opt/data/goaccess-sample/geoip/) - 分析样本:
/opt/data/goaccess-sample/access.log(nginx Combined 格式,53 行,覆盖 200/404/405 状态与 GET/POST/DELETE/PATCH/HEAD 方法、Chrome/Firefox/Edge/curl 等多种 UA) - 相关目录:报告输出
/tmp/goaccess-rt/、持久化库/tmp/ga-db/
二、前置条件
确认命令可用与样本就位:
which goaccess && goaccess --version | head -1
wc -l /opt/data/goaccess-sample/access.log
实测回显:
/usr/local/bin/goaccess
GoAccess - 1.9.4.
53 /opt/data/goaccess-sample/access.log
三、命令语法与全局选项
GoAccess 的命令行骨架只有三种形态:
goaccess <日志文件> [选项] # 直读文件
goaccess <日志文件> --output=<文件> # 直接产出报告
goaccess - [选项] # 从标准输入读日志
核心约定(实测确认,遗漏即报错):
-是"从标准输入读日志"的专用参数——管道模式必须以-收尾;写漏时会报没有提供输入数据,也没有要恢复的数据(见 10.3 排障)。--log-format是每次分析的必需参数(除非已写入配置文件);预定义名COMBINED无需再传 time/date-format。--output的文件扩展名决定输出形态:.html/.json/.csv。- 多个
--output可同时使用(如同时产出 HTML 与 JSON),一次解析多形态输出。
常用全局选项速查(完整语义见配置文件注释):--log-format、--date-format、--time-format、--output、--real-time-html、--port、--addr、--daemonize、--pid-file、--persist、--restore、--db-path、--geoip-database、--ignore-panel、--exclude-ip、--date-spec、--hour-spec、--json-pretty-print、--num-tests、--invalid-requests、--config-file、--no-global-config、--help。
四、四种输出形态分析矩阵
本节给出同一份日志在四种形态下的完整命令与真实回显,构成日常分析的"命令矩阵"。
4.1 终端 TUI(交互界面)
goaccess /opt/data/goaccess-sample/access.log --log-format=COMBINED
实测界面渲染文字(53 行样本,概览栏与"每日独立访客"面板节选;界面随 locale 中文显示):
GoAccess 1.9.4 概览-所有已分析的请求 (17/10月/2026 - 17/10月/2026)
所有请求50 独立访客5 请求的文件14 来源地址0 有效的请求50 日志解析耗时1s
静态文件3 日志大小7.91 KiB 失败的请求0 未找到(404) 27 数据传输量13.30 KiB
日志文件夹地址 /opt/data/goaccess-sample/access.log [当前面板: 访客]
1 - 每日独立访客 - 包括网络机器人 总共: 1/1
点击量 h% 访客 v% 数据传输量 数据
50 100.00% 5 100.00% 13.30 KiB 17/10月/2026
常用交互键(实测有效):1-17 数字键或 Tab 切换面板、j/k 或方向键滚动、s 面板内排序、g 跳到面板首行、q 退出当前面板或整个程序、h 帮助、c 配色方案。TUI 适合排查时的即时查看,退出后不留产物。
4.2 HTML(静态报告)
goaccess /opt/data/goaccess-sample/access.log --log-format=COMBINED \
--geoip-database=/opt/data/goaccess-sample/geoip/GeoLite2-Country.mmdb \
--output=/tmp/goaccess-quick.html
ls -la /tmp/goaccess-quick.html
实测回显:
-rw-r--r-- 1 root root 735009 10月 17 16:43 /tmp/goaccess-quick.html
产出约 735KB 的单文件 HTML——全部样式、图表脚本与统计数据内嵌,拷到任意位置或用 nginx 托管即可打开,无外链依赖,天然适配内网与归档。
4.3 JSON(结构化数据)
goaccess /opt/data/goaccess-sample/access.log --log-format=COMBINED --output=/tmp/ga-test.json
python3 -c 'import json; d=json.load(open("/tmp/ga-test.json")); g=d["general"]; print(g["total_requests"], g["unique_visitors"], g["unique_not_found"]); print([ (r["data"], r["hits"]["count"]) for r in d["requests"]["data"][:3] ])'
实测回显:
53 5 27
[('/notfound-page', 2), ('/old/blog/2019.html', 1), ('/wp-admin/setup.php', 1)]
JSON 形态输出全部 17 个面板的结构化数据(压缩单行约 21KB;加 --json-pretty-print 变为 1973 行缩进),是接入监控脚本、告警阈值判断与二次可视化的首选形态。
4.4 CSV(表格导入)
goaccess /opt/data/goaccess-sample/access.log --log-format=COMBINED --output=/tmp/ga-report.csv
head -6 /tmp/ga-report.csv
实测回显:
"0",,"general",,,,,,,,"2026-10-17 16:29:50 +0800","date_time"
"1",,"general",,,,,,,,"50","total_requests"
"2",,"general",,,,,,,,"50","valid_requests"
"3",,"general",,,,,,,,"0","failed_requests"
"4",,"general",,,,,,,,"1","generation_time"
"5",,"general",,,,,,,,"5","unique_visitors"
CSV 以"序号,面板,值,键名"逐行组织汇总指标与各面板数据,直接可被 Excel、Python pandas(pd.read_csv)等导入,适合交付给数据同事做进一步计算。
命令矩阵小结:
| 目标 | 命令模板 | 产物 |
|---|---|---|
| 交互速览 | goaccess log --log-format COMBINED | 终端界面 |
| 交付报告 | goaccess log --log-format COMBINED --output=out.html | 单文件 HTML |
| 程序消费 | goaccess log --log-format COMBINED --output=out.json | 结构化 JSON |
| 表格导入 | goaccess log --log-format COMBINED --output=out.csv | CSV |
五、常用命令组合
本节把高频实战场景打包成可复制的完整命令行。
组合一:离线静态报告 + 地理位置分析(cron/一次性):
goaccess /var/log/nginx/access.log \
--log-format COMBINED \
--geoip-database /opt/data/goaccess-sample/geoip/GeoLite2-Country.mmdb \
--output /var/www/html/goaccess/report-$(date +%F).html
实测同类命令产物:/tmp/goaccess-quick.html(735KB),文件名带日期便于按日归档。
组合二:实时 HTML 大屏(管道常驻):
tail -F -n0 /var/log/nginx/access.log | goaccess --log-format COMBINED \
--real-time-html --port=7890 \
--output=/var/www/html/goaccess/report.html -
实测回显(启动后端口监听与日志提示):
LISTEN 0 4096 0.0.0.0:7890 0.0.0.0:* users:(("goaccess",pid=2294384,fd=8))
WebSocket服务器已准备接收来自客户的连接
实测刷新验证:流内新增 1 行请求后,浏览器报告的 total_requests 从 53 即时变为 54(见第九章 systemd 托管)。
组合三:远端日志本地分析(跨机管道):
ssh user@web01 "tail -F -n0 /var/log/nginx/access.log" \
| goaccess --log-format COMBINED --real-time-html --port=7890 \
--output=/var/www/html/goaccess/web01.html -
无需在 web01 安装任何东西,用 SSH 把远端日志流接进本地 GoAccess;生产建议将 SSH 免密与连接保活(-o ServerAliveInterval=30)写入该命令。
组合四:格式试跑校准(接入新日志源的第一步):
goaccess /var/log/nginx/access.log --log-format COMBINED \
--num-tests=10 --invalid-requests=/tmp/invalid.log --output=/dev/null
实测有效:解析 10 行试验若失败,错误行会写入 /tmp/invalid.log 供比对其格式差异。
组合五:只看某个维度的轻量分析:
# 剔除内网探活 IP 后看真实访客
goaccess /var/log/nginx/access.log --log-format COMBINED \
--exclude-ip 10.0.0.0-10.255.255.255 --output=/tmp/real-users.json
# 忽略静态资源后的"有效请求"视角
goaccess /var/log/nginx/access.log --log-format COMBINED \
--ignore-statics=req --output=/tmp/dynamic-only.json
# 只看爬虫
goaccess /var/log/nginx/access.log --log-format COMBINED \
--crawlers-only --output=/tmp/crawlers.json
六、多日志合并分析
nginx 按日轮转后日志分散在多个文件(access.log、access.log.1、access.log.2.gz),GoAccess 支持三种合并姿势。
方式一:cat 顺序拼接管道(最常用):
cat /tmp/log-a.log /tmp/log-b.log | goaccess --log-format COMBINED --output=/tmp/ga-merge.json -
实测回显(25 行 + 25 行两个切片合并):
merged total: 50
方式二:通配符多文件直读(1.7+ 支持位置参数展开为多文件):
goaccess /var/log/nginx/access.log* --log-format COMBINED --output=/tmp/all.html
方式三:gzip 压缩日志 zcat 管道(跨轮转周期合并时必需):
gzip -c /opt/data/goaccess-sample/access.log > /tmp/access.log.gz
zcat /tmp/access.log.gz | goaccess --log-format COMBINED --output=/tmp/ga-gz.json -
实测回显:
zcat-pipe total: 53
⚠️ 注意:1.9.4 不能直读
.gz文件——实测goaccess /tmp/access.log.gz --log-format COMBINED --output=...解析 0 行退出(压缩日志直读依赖编译期 zstd 支持,本文构建未开启,gzip 亦不受支持)。旧压缩包必须经zcat管道;若日志量极大可用--enable-zstd重新编译获得原生压缩支持。
⚠️ 注意:合并多台服务器的日志时,各机 log-format 必须一致;
--log-format在命令行中只写一次,作用于全部输入。
七、按日期与小时粒度分析
GoAccess 没有"只分析某个时间段"的过滤参数,粒度控制靠两个维度参数 + 日志切分实现。
参数一:--date-spec=hr(访客面板按小时聚合):
goaccess /opt/data/goaccess-sample/access.log --log-format COMBINED \
--date-spec=hr --output=/tmp/ga-hr.json
python3 -c 'import json; d=json.load(open("/tmp/ga-hr.json")); print([x["data"] for x in d["visitors"]["data"]]); print([(x["data"], x["hits"]["count"]) for x in d["visit_time"]["data"]])'
实测回显:
['2026101708', '2026101707']
[('07', 19), ('08', 34)]
访客键由 20261017(日)变为 2026101708(小时);配合 --date-spec=min 可到分钟级。
参数二:--hour-spec=min(时段面板 10 分钟粒度):默认时段面板键为小时(如上回显 07/08),加 --hour-spec=min 后变为 07:30 这类 10 分钟键。
按日期切分日志再分析(真正的时间过滤):要"只看 10 月 16 日的访问",在输入侧完成过滤:
# 单文件内按日期 grep
grep '16/Oct/2026' /var/log/nginx/access.log | goaccess --log-format COMBINED --output=/tmp/oct16.json -
# 已按天轮转的日志直接指定对应文件
goaccess /var/log/nginx/access.log.1 --log-format COMBINED --output=/tmp/yesterday.html
grep 过滤与粒度参数组合可覆盖"每小时报表""任意时间段回溯"两类需求;周期性场景优先用轮转文件而非 grep(避免全量扫描)。
八、增量分析:persist 与 restore
面对持续增长的日志,"每次全量重算"不可持续。GoAccess 的增量方案由三个参数构成:--db-path(数据库目录)、--persist(退出时写盘)、--restore(启动时读盘),三者组合即可实现"数据越滚越多、处理越来越快"。
第 1 步:全量解析并落盘:
goaccess /opt/data/goaccess-sample/access.log --log-format COMBINED \
--persist --db-path=/tmp/ga-db --output=/tmp/p1.json
ls /tmp/ga-db/*.db | wc -l
实测回显:
151
落盘 151 个面板数据文件(每面板一组 key-value .db)。
第 2 步:空输入从磁盘恢复(验证数据可独立于日志存在):
goaccess --log-format COMBINED --restore --db-path=/tmp/ga-db --output=/tmp/p2.json
python3 -c 'import json; d=json.load(open("/tmp/p2.json")); print("restored total:", d["general"]["total_requests"])'
实测回显:
restored total: 53
第 3 步:喂新日志做增量(恢复 + 追加 + 回写一条龙):
tail -1 /opt/data/goaccess-sample/access.log > /tmp/new-line.log
goaccess /tmp/new-line.log --log-format COMBINED \
--restore --persist --db-path=/tmp/ga-db --output=/tmp/p3.json
python3 -c 'import json; d=json.load(open("/tmp/p3.json")); print("incremental total:", d["general"]["total_requests"])'
实测回显:
incremental total: 54
53 → 54,增量语义正确。--restore --persist 成对出现是增量分析的标准姿势:先读旧库、合并新日志、写回新库。
配套参数:--keep-last 30 只保留最近 30 天数据(控制库体积);轮转日志场景建议配合 7.1 的日志切分(每天一份),将"已入库的旧日志"移出增量队列。
⚠️ 注意:1.9 版本起
--load-from-disk已更名为--restore(实测 1.9.4 传旧名报unrecognized option);且持久化数据库格式随版本演进,跨大版本升级后建议先备份配置文件、清空 db-path 重建数据库。
九、定时报告:systemd timer 方案
真实服务器上"每小时/每天出一份报告"不建议用裸 cron,systemd timer 自带持久化(错过的触发点开机补跑)、日志进入 journal、状态可查询。完整方案两件套:
单元文件:
mkdir -p /var/www/html/goaccess /var/lib/goaccess
cat > /etc/systemd/system/goaccess-report.service <<'EOF'
[Unit]
Description=GoAccess daily HTML report generator
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/goaccess /opt/data/goaccess-sample/access.log --log-format=COMBINED --output=/var/www/html/goaccess/report.html --persist --db-path=/var/lib/goaccess
EOF
cat > /etc/systemd/system/goaccess-report.timer <<'EOF'
[Unit]
Description=Run GoAccess report hourly
[Timer]
OnCalendar=hourly
Persistent=true
[Install]
WantedBy=timers.target
EOF
设计说明:service 为 oneshot(跑完即退);ExecStart 中 --persist --db-path 让每次报告把统计写进 /var/lib/goaccess,若再追加 --restore 参数即从第 N 次起全时段累积(首跑先建库)。OnCalendar=hourly 每整点触发,改为 OnCalendar=*-*-* 00:00:00 即每日零点;Persistent=true 保证停机错过的时间点开机后补跑。
启用与触发:
systemctl daemon-reload
systemctl enable --now goaccess-report.timer
systemctl start goaccess-report.service
实测回显:
Created symlink /etc/systemd/system/timers.target.wants/goaccess-report.timer → /etc/systemd/system/goaccess-report.timer.
NEXT LEFT LAST PASSED UNIT ACTIVATES
Sat 2026-10-17 17:00:00 CST 16min left n/a n/a goaccess-report.timer goaccess-report.service
1 timers listed.
执行状态验证:
systemctl status goaccess-report.service --no-pager -l | head -6
ls -la /var/www/html/goaccess/
实测回显:
● goaccess-report.service - GoAccess daily HTML report generator
Loaded: loaded (/etc/systemd/system/goaccess-report.service; static)
Active: inactive (dead) since Sat 2026-10-17 16:43:50 CST; 15ms ago
Process: 2310852 ExecStart=/usr/local/bin/goaccess /opt/data/goaccess-sample/access.log --log-format=COMBINED --output=/var/www/html/goaccess/report.html --persist --db-path=/var/lib/goaccess (code=exited, status=0/SUCCESS)
total 728
-rw-r--r-- 1 root root 735009 10月 17 16:43 report.html
status=0/SUCCESS、735009 字节报告与 /var/lib/goaccess/ 下的持久化库均按预期生成。
运营技巧:报告页由 nginx 托管 /var/www/html/goaccess/ 即可全队访问;文件名模板 --output=/var/www/html/goaccess/report-$(date +%F).html 无法直接写入 unit(unit 不做 shell 展开),改为把 ExecStart 指向一个包装脚本,在脚本内完成日期命名与旧报告清理。
十、常见问题(FAQ)
Q1:--real-time-html 模式下报告不更新?
根因:文件直读模式读到 EOF 后不再监控文件增长(实测进程 fd 表中无日志文件句柄)。解决:一律改用管道模式 tail -F -n0 日志 | goaccess ... -(-F 可跟随轮转重命名,-n0 避免启动时重复计入旧数据),实测新增日志后报告秒级刷新(53 → 54)。
Q2:Unable to set bind: Address already in use. 后退出?
WebSocket 端口(默认 7890)被旧实例占用。解决:
ss -tlnp | grep 7890
pkill -x goaccess
或启动时 --port=7891 换端口。
Q3:报 没有提供输入数据,也没有要恢复的数据?
管道模式漏写收尾的 - 参数——goaccess 找不到输入源(实测 zcat access.log.gz | goaccess --log-format COMBINED --output=... 复现此错,补上 - 后 53 行全部解析成功)。另注意:--load-from-disk 在 1.9.4 上须写 --restore,否则同样被视作"没有要恢复的数据"。
Q4:.gz 压缩日志能直接读吗?
不能(实测解析 0 行退出)。1.9.4 的压缩直读仅支持编译期开启 zstd 的构建;gzip 日志用 zcat access.log.gz | goaccess ... - 管道读入,或对大日志量用 --enable-zstd 重新编译。
Q5:多文件合并时方法/URL 统计翻倍不对?
检查两处:各文件 log-format 是否一致;是否把轮转边界(access.log 与 access.log.1 存在同一时间段的重叠行)重复统计。轮转配置用了 copytruncate 时特别容易出现重叠。
Q6:定时任务跑了但报告没更新?
先看服务退出码:systemctl status goaccess-report.service 的 code=exited, status=0/SUCCESS 行;非 0 时 journalctl -u goaccess-report.service -n 50 看具体报错(常见为路径权限——db-path 与 output 目录需对运行用户可写,或 log-format 传参引号丢失)。
十一、参考链接
- goaccess(1) 手册页(全命令行参数):https://man.archlinux.org/man/goaccess.1
- GoAccess GitHub 仓库:https://github.com/allinurl/goaccess
- 官网文档首页:https://goaccess.io/docs
- systemd timer 官方手册:https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html
- nginx 官方文档(log_format 指令):https://nginx.org/en/docs/http/ngx_http_log_module.html