关于GoAccess的损耗,因为网络上的教程基本是基于ELK(Elasticsearch , Logstash, Kibana),有点担心GoAccess影响服务器性能。在GoAccess官网的faq中,刚好有一个问题答疑,题目是
How fast is GoAccess when parsing a log file?
大致翻译如下:许多因素会影响解析时间,包括处理器,内存,日志等。但是,通常我们可以得出下表: 在基准测试的前提为Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz 16GB RAM 情况下,最少能处理100,502行日志/秒,而400百万的匹配(文件大小74G)可以于内存中在1小时20分钟内处理完成,损耗约12GB RAM。在使用内存泄漏工具Valgrind检测时,GoAccess没有泄漏任何内存。启用完整功能的前提下,解析3,397,814行占用134.1 MiB(内存)。删除-q查询字符串可以大大减少内存消耗,尤其是在带有时间戳的请求上。
按照官网的步骤如下
1.下载GoAccess。在配置时,官网推荐选项如下:
./configure --enable-utf8 --enable-geoip=legacy
- enable-utf8:具有广泛的字符支持编译。必须 安装Ncursesw。
- enable-geoip=legacy:与GeoLocation支持一起编译。必须使用MaxMind的GeoIP。旧版将使用原始的GeoIP数据库。
几个报错的问题如下,
configure: error:
*** Missing development files for the GeoIP library
缺少GeoIP,先配置epel仓库,然后搜寻GeoIP包,安装该包
yum install epel-release
再安装ncurses-devel。出现如下画面,则说明配置成功。
2.编译安装之后,可以开始使用。最基本的用法就是在命令行输入,看到如下画面。
goaccess access.log -c
选择一个格式进入之后,大概是这么个样子,对应的nginx日志我也放在下面(我将nginx日志已经全部清空)
总请求2,独立访问的用户1个,可以看到我访问了首页,其实是发出了两个请求,自动请求了首页logo(404),下面其实还有一些请求文件(请求方式、协议),未找到的URL,访问者地理位置等内容,不一一介绍了。
测试中我发现,这个独立访问者有些问题,例如,nginx中实际统计的访问人数是26人,但是上面的独立访客一直显示的是16人,按照我的理解,26个独立IP怎么的也得算26个Unique Visitors了吧,尤其是我去查了官方手册之后
awk '{print $1}' access.log | sort | uniq -c | awk '{print $2}' | wc -l
>>>26
官方手册,其中关于唯一访问者的介绍是
Unique visitors: This panel shows metrics such as hits, unique visitors and cumulative bandwidth per date. HTTP requests containing the same IP, the same date, and the same user agent are considered a unique visitor. By default, it includes web crawlers/spiders.
Optionally, date specificity can be set to the hour level using --date-spec=hr which will display dates such as 05/Jun/2016:16, or to the minute level producing 05/Jun/2016:16:59. This is great if you want to track your daily traffic at the hour or minute level.
蹩脚翻译:包含相同IP,相同日期和相同用户代理的HTTP请求被视为唯一访问者,这句话应该想表达的是只要IP,日期,或者UA不一样,则代表用户是一个独立的访问者,因为同一个局域网络中(公网IP相同)通过安卓机、电脑、平板访问同一个网站他们的UA不同。看完我就更懵了,按照这么说,独立访问者大部分时候应该比独立IP更多呗,这咋还少一些,没有查到相关的资料,我就带着这个疑惑进入了第三步。
3.生成静态HTML报告。
goaccess access.log -o report.html --log-format=COMBINED
将report.html迁移至nginx访问目录下,我们到前台看下是个什么东西,哟,还蛮酷炫。
在这里面找到Visitor Hostnames and IPs,如下图所示,找到最下面统计那一行,总统计数69,唯一访问者16,后面还有一个数字26,就是访问的去重后的IP数。关于Unique Visitors(感觉翻译成不重复访问者比较好一点,因为IP,UA,DATA任选其一不重复则会计入其中),我的理解是一个独立的IP过来访问,你的页面返回状态码的是200类型,才会被计入到Unique Visitors(所以这就解释了上面第二步的问题)。
例如上图中的第2个IP:43.254.151.94,在nginx中总共有9条访问记录,其中,状态码为200的只有一条,所以请求9,访问1。
再例如,上面第3个IP:40.72.109.61,我也去nginx中查了它的访问记录,下图,可以很清楚的看到3条访问记录,均为404,所以请求3,访问者0(因为它一个页面都没有访问到)
综上,Unique Visitors指的是用户请求网站页面成功次数的总和(或者可以叫做成功访问网站用户数),即Visitors那一列的所有数字相加。
4.如何生成动态实时的html报告?
首先需要配置nginx文件的路由,例如我的报告内容均生成在以下目录,名字为index.html。
/usr/local/nginx/html/report
在后台运行goaccess,命令如下,port是指定WSS通过9870端口来传输数据(我的防火墙已经放行了该端口),如果不设置,则默认为7890端口;exclude-ip指在统计页面中不统计这个IP(我的公网IP),当然, Total Requests中还是会计入 这个IP的访问,但是在Visitor Hostnames and IPs一栏中就可以看到我的IP统计全部消失了。
goaccess access.log -o /usr/local/nginx/html/report/index.html --real-time-html --port=9870 --exclude-ip=150.40.04.1
配置nginx文件,新建一个虚拟主机,监听8080端口
server {
listen 8080;
location /report {
alias /usr/local/nginx/html/report;
}
}
在访问8080端口report目录时,返回index.html,需要注意的是,该页面只是一个静态页面,其数据变化其实是依赖于WebSocket,所以一旦在后台停止了goaccess,那么这个页面立刻就会恢复到刚生成的静态页面。
当然,这个页面不可能每个人都能访问,所以还需要在该页面设置一个登录验证。利用nginx也很容易实现,参考Nginx作为web服务器的功能以及虚拟主机的作用。
dnf install -y httpd-tools
# 配置nginx.conf,虚拟主机中加入以下代码
auth_basic "zhang";
auth_basic_user_file /usr/local/nginx/pwd/htpasswd;
# 创建文件夹
mkdir /usr/local/nginx/pwd
# 以命令行形式添加密码,并自动创建密码文件htpasswd
htpasswd -b -c /usr/local/nginx/pwd/htpasswd zhangxiaofei 123456
>Adding password for user zhangxiaofe
前端页面必须通过账户密码验证才可访问。
5.如果不想每次人工去运行goaccess,也可以获取实时的报告,有两种方案,一种是写一个crontab脚本定时运行,每次重新输出一个静态页面,因为其实这个前端页面访问的是nginx的html目录下的某个文件,这种方法适合服务器资源较紧张,对日志实时性要求不高的用户,例如
touch nginx_logs.sh
chmod o+x nginx_logs.sh
# nginx_logs.sh脚本内存如下
#!/bin/bash
# 显示中文界面,似乎无效
LANG="zh_CN.UTF-8"
counts=$(lsof -i :7890 | wc -l)
if [ $counts -ne 0 ]
then
killall goaccess;
/usr/local/bin/goaccess /usr/local/nginx/logs/access.log -o /usr/local/nginx/html/report/index.html -p /usr/local/etc/goaccess/goaccess.conf
else
/usr/local/bin/goaccess /usr/local/nginx/logs/access.log -o /usr/local/nginx/html/report/index.html -p /usr/local/etc/goaccess/goaccess.conf
fi
# 定时脚本
crontab -e
*/1 * * * * /bin/bash /usr/local/nginx/logs/nginx_logs.sh
脚本的含义是先判断goaccess启动了没,如果7890端口被占用,我判断它已经启动,并kill掉重新输出一个html文件,如果7890端口没被占用,那么启动goaccess即可,这样前台访问的静态页面也是每分钟就会刷新一次。
另外一种方法就是加入--daemonize参数以守护进程启动。需要注意下面的路径都要使用绝对路径!
goaccess /usr/local/nginx/logs/access.log -o /usr/local/nginx/html/report/index.html --real-time-html --daemonize
# 查看是否启动
Daemonized GoAccess: 36248
ps aux | grep goaccess
可以看到已经顺利启动。
6.关于goaccess日志格式,解释如下
- %t 匹配time-format格式的时间字段
- %d 匹配date-format格式的日期字段
- %h host(客户端ip地址,包括ipv4和ipv6)
- %r 来自客户端的请求行
- %m 请求的方法
- %U URL路径
- %H 请求协议
- %s 服务器响应的状态码
- %b 服务器返回的内容大小
- %R HTTP请求头的referer字段
- %u 用户代理的HTTP请求报头
- %D 请求所花费的时间,单位微秒
- %T 请求所花费的时间,单位秒
- %^ 忽略这一字段
我来贴一段nginx的日志以及nginx配置文件中的log_format
119.36.11.83 - zhangxiaofei [31/Jan/2021:06:26:42 +0000]
"GET /report/ HTTP/1.1" 200 382732 "-"
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0" "-"
# 配置文件nginx.conf
log_format main
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
然后再看下/usr/local/etc/goaccess/goaccess.conf文件,就能够明白这个日志格式是怎么对应的了。
# NCSA Combined Log Format
log-format %h %^[%d:%t %^] "%r" %s %b "%R" "%u"
%h对应的$remote_addr,第二个%^参数忽略,第三个[%d:%t %^]对应的是nginx[$time_local]的31/Jan/2021和06:26:42,+0000省略,第四个"%r"对应的"$request",第五个%s对应的$status,以此类推。
7.如果要通过TLS / SSL连接输出实时数据,需要使用--ssl-cert = <cert.crt>和--ssl-key = <priv.key>,这些也可以在goaccess.conf配置文件中直接修改,当然,在源码配置之前需要加入--with-openssl。
参考资料:
#goaccess
https://goaccess.io/get-started
https://goaccess.io/man
#I find the value of "unique visitors" is not right!
https://github.com/allinurl/goaccess/issues/1205