背景
大家自建博客有没有统计过自己的访问量,每天有多少访问者,每天有多少点击量。这些信息其实都可以通过Nginx
的访问日志来获取,通过Linux
的命令就可以完成,比如昨天的访问数(IP计数):
1
| grep -hF "$(date -d 'a day ago' +%d/%b/%Y)" /var/log/nginx/access.log* | awk '{print $1}' | sort | uniq | wc -l
|
但是这种方式不但操作繁琐,输出的结果也很简单,无法满足我们进一步的需求,比如写个 ppt 给领导看,工作组内通报网站运行情况。
今天我们就像大家介绍一个可视化的网站访问统计工具 - GoAccess。
安装
GoAccess
安装还是非常简单的:
1
| sudo apt install goaccess
|
但是,ubuntu
默认仓库的GoAccess
版本比较老,可以添加GoAccess
官方仓库安装最新版本,只不过下载速度堪忧。
1
2
3
4
5
6
| wget -O - https://deb.goaccess.io/gnugpg.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/goaccess.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/goaccess.gpg arch=$(dpkg --print-architecture)] https://deb.goaccess.io/ $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/goaccess.list
sudo apt-get update
sudo apt-get install goaccess
|
配置
由于GoAccess
是通过读取Nginx
的访问日志来统计数据,所以首先我们就需要让GoAccess
知道Nginx
的日志格式,主要包括以下几个参数
- time-format : 时间格式,默认为
%H:%M:%S
- date-format : 日期格式,默认为
%d/%b/%Y
- datetime-format : 完整的时间戳
%d/%b/%Y:%H:%M:%S %z
- log-format : 日志条目格式,可选格式较多,需要与
Nginx
的log_format
定义保持一致,这也是goaccess
配置的难点
以上参数可以通过编辑/etc/goaccess/goaccess.conf
进行修改。下面是我的Nginx
日志格式:
1
2
3
4
| log_format main '$remote_addr $host:$server_port - $remote_user '
'[$time_local] "$request" $status $body_bytes_sent '
'$request_length $request_time $upstream_response_time '
'"$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
|
这里是Nginx
一行日志的格式,但为了配置文件的美观,我将其分成了多行。但是,也因此犯了一个小小的错误。由于GoAccess
是通过空格来分割不同部分,而我在body_bytes_sent
的行尾少加了一个空格,导致所有Nginx
日志的body_bytes_sent
及其后面部分都无法正常解析。
正常打印出来的日志是这样子的:
1
| 61.141.138.241 img.mtdcy.top:8443 - - [15/Dec/2023:11:07:12 +0800] "GET /i/2023/12/14/qjbrsd-2.webp HTTP/2.0" 200 9840 383 0.000 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0" "-"
|
对应GoAccess
的配置为:
1
| log-format %h %v:%^ %^ %e [%d:%t %^] "%r" %s %b %T %^ "%R" "%u" "%^"
|
详细参数格式请参数man goaccess
或官方文档。
现在我们的GoAccess
已经可以运行了,是不是很惊艳:
终端实时监控
如上图所示,我们可以通过以下命令打开终端,实时统计Nginx
访问数据:
- 每天的独立访客量
- 访问文件统计
- 访客IP、操作系统和浏览器
- 访问的时间分布
- 虚拟主机访问量
- ……
1
| goaccess /var/log/nginx/access.log
|
输出访问统计为HTML
GoAccess
的优秀之处就在于,其不但可以将统计数据输出到终端上实时查看,还可以将统计数据输出为单HTML文件,并分享给其他人查看。
1
| goaccess /var/log/nginx/access.log -a > report.html
|
(大家就忽略TX. AMOUNT
数据吧,这就是我前面提到的错误。)
是不是很优秀,现在我们再也不担心写 PPT 时没数据表格了,给领导报告也有了直观的数据表格。
我的应用场景
目前我打算将GoAccess
作为博客访问统计的默认工具。整个方案设计如下:
- 通过
autoindex
建立一个文件服务器; - 使用
GoAccess
生成实时统计数据; - 每天、每星期、每月统计一次历史数据并保存;
文件服务器
我们经常在开源网站看到如下界面,其实这只需要简单设置Nginx
几个参数即可:
1
2
3
| autoindex on; # enable directory listing output
autoindex_exact_size off; # output file sizes rounded to kilobytes, megabytes, and gigabytes
autoindex_localtime on; # output local times in the directory
|
这里就不深入了,后面我再专门写一篇文章介绍Ningx
文件服务器。
这里建立文件服务器的目标主要为了快速查看GoAccess
生成的统计文件。
生成实时统计数据
GoAccess
另一个优秀之处在于,其内置websocket
,这就使得其生成的HTML也可以做到实时更新。另外,其生成HTML不但可以分享给他人,还可以在文件服务器的任何路径打开,不受 root url 影响。
1
| goaccess /var/log/nginx/access.log -o /path/to/reports/now.html --real-time-html --keep-last=7 &
|
GoAccess
甚至还支持https
:
1
2
3
4
5
| goaccess /var/log/nginx/access.log \
--ssl-cert=/etc/letsencrypt/live/<domain>/fullchain.pem \
--ssl-key=/etc/letsencrypt/live/<domain>/privkey.pem \
--real-time-html --keep-last=7 \
-o /path/to/reports/now.html &
|
你可以直接将这条命令放入rc.local
,开机自动开始实时数据统计。
定时统计历史数据
这里,我们设计是每天、每星期、每月定时统计一次历史数据。这里需要两个小脚本帮助我们统计数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| #!/bin/bash
# usage: report.sh N destination
# if includes days of last month, the behavior is undefined.
cd "$(dirname $0)"
N=${1:-1} # number of days ago
D=${2:-daily} # destination to write
DATE="$(eval date -d \"$N day ago\" '+%Y-%m-%d\ 00:00:00')"
ALT="$(eval date -d \"$DATE\" '+[%d/%b/%Y:')"
find /var/log/nginx/ -name "*access.log*" -type f -newermt "$DATE" |
while read -r file; do
[[ "$file" =~ ^.+\.gz$ ]] && cmd="zcat" || cmd="cat"
$cmd "$file" | awk -v Date="$ALT" '$5 > Date {print $0}'
done | goaccess -o "./$D/$(date '+%Y-%m-%d').html" -
|
将其保存为report.sh
,这个脚本的功能是统计 N 天前到现在的数据,并将统计结果保存到指定目录。
1
2
3
4
5
6
7
8
| #!/bin/bash
cd "$(dirname $0)"
for file in /var/log/nginx/access.log*; do
[[ "$file" =~ ^.+\.gz$ ]] && cmd="zcat" || cmd="cat"
$cmd "$file"
done | goaccess -o "./monthly/$(date '+%Y-%m-%d').html" -
|
保存第二个脚本report-monthly.sh
。这个脚本相对比较简单,主要功能就是统计所有历史访问记录,将结果保存到monthly
目录。这里每月统计依赖于logrotate
,默认情况logrotate
为Nginx
保存的日志都比较短,比如Ubuntu
上就只有 15 天。这里我们需要修改/etc/logrotate.d/nginx
将保存的日志数量调整为 30 天,这样就实现了monthly
统计。
接下来就是使用crontab
设置定时任务,在crontab -e
中添加如下设置:
1
2
3
4
| # goaccess
0 0 * * * /path/to/report.sh 1 daily
0 0 * * 1 /path/to/report.sh 7 weekly
0 0 1 * * /path/to/report-monthly.sh
|
最终效果图如下,点击相应目录即可查看历史统计数据。
结束语
我相信能够做到Nginx
访问统计的工具很多,比如Nginx Amplify
,但GoAccess
的优秀之处就在于其无需额外的服务,本身也就依赖于Nginx
和ncurses
等系统自带库文件,可以说是足够短小精悍;另外,其不但可以在终端实时查看,生成的 HTML 文件也无依赖,可通过邮件等分享给他人;还有,其还可以通过Websocket
实现在 Web 端实时查看统计数据。而这些都只需要通过一条简单的命令goaccess
。