Featured image of post 好物推荐 - GoAccess

好物推荐 - GoAccess

一款Nginx日志分析和统计工具

背景

大家自建博客有没有统计过自己的访问量,每天有多少访问者,每天有多少点击量。这些信息其实都可以通过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 : 日志条目格式,可选格式较多,需要与Nginxlog_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已经可以运行了,是不是很惊艳:

IMG_20231216_110922

终端实时监控

如上图所示,我们可以通过以下命令打开终端,实时统计Nginx访问数据:

  • 每天的独立访客量
  • 访问文件统计
  • 访客IP、操作系统和浏览器
  • 访问的时间分布
  • 虚拟主机访问量
  • ……
1
goaccess /var/log/nginx/access.log

输出访问统计为HTML

GoAccess的优秀之处就在于,其不但可以将统计数据输出到终端上实时查看,还可以将统计数据输出为单HTML文件,并分享给其他人查看。

1
goaccess /var/log/nginx/access.log -a > report.html 

IMG_20231216_112327 (大家就忽略TX. AMOUNT数据吧,这就是我前面提到的错误。)

是不是很优秀,现在我们再也不担心写 PPT 时没数据表格了,给领导报告也有了直观的数据表格。

我的应用场景

目前我打算将GoAccess作为博客访问统计的默认工具。整个方案设计如下:

  1. 通过autoindex建立一个文件服务器;
  2. 使用GoAccess生成实时统计数据;
  3. 每天、每星期、每月统计一次历史数据并保存;

文件服务器

我们经常在开源网站看到如下界面,其实这只需要简单设置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,默认情况logrotateNginx保存的日志都比较短,比如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 

最终效果图如下,点击相应目录即可查看历史统计数据。

IMG_20231216_114949

结束语

我相信能够做到Nginx访问统计的工具很多,比如Nginx Amplify,但GoAccess的优秀之处就在于其无需额外的服务,本身也就依赖于Nginxncurses等系统自带库文件,可以说是足够短小精悍;另外,其不但可以在终端实时查看,生成的 HTML 文件也无依赖,可通过邮件等分享给他人;还有,其还可以通过Websocket实现在 Web 端实时查看统计数据。而这些都只需要通过一条简单的命令goaccess


最后更新于 2024-12-07
小酌怡情
Built with Hugo
主题 StackJimmy 设计
访问量 -    访客数 - 人次