服务器日志分析利器:ngxtop和GoAccess-实时监控可视化管理快速找出异常来源

最近“贪图”便宜,将服务器换到了阿里云国际版香港VPS主机。搬过来后最大的感觉并不是速度的提升——因为原来用的韩国kdatacenter VPS在电信网络访问也是挺快的——而是阿里云VPS主机的性能相对于同样是1GB的其它VPS主机来说真的有点弱了。

稍微用工具一扫阿里云香港VPS的系统负载就蹭蹭往上涨,有时刚在后台写文章就发现打不开了。打开服务器日志一看,发现了不少的异常IP,例如扫描端口的,还有SQL注入的,还有“捡漏”网站备份文件的,还有AB压力测试的……总之,出现不少的非人为的访问行为。

分析日志中的IP行为是一个比较累人的苦力活,尤其是当日志达到几百MB以上时,用文本文件打开就非常地缓慢了。本篇文章就来分享两个优秀的服务器日志分析工具:ngxtop和GoAccess。ngxtop 是通过分析 Nginx 日志文件,使用类似 top 命令的界面实时展示出来的。

ngxtop可以分析以前的日志文件,也可以实时监控服务器日志,你可以像用Top命令一样在端口中快速查出日志中访问最多的IP地址、403/500/404错误、请求的页面排行等等。ngxtop是一个轻量级的工具,而GoAccess则更像是强大的日志统计工具。

GoAccess不仅图文并茂,而且速度快,每秒8W 的日志记录解析速度,websocket每10秒刷新统计数据。GoAccess不仅有命令行界面,也可以生成一个Html网页,让你直观地看出来日志中访客数量、请求的文件、404等错误、用户位置、浏览器、操作系统、来路URL、Http状态码等。

服务器日志分析利器:ngxtop和GoAccess-实时监控可视化管理快速找出异常来源

总之,ngxtop和GoAccess是两款分析Apache、Nginx等服务器日志的利器,掌握好了这两个软件,那些对服务器“潜在”的危险IP即可显露“原形”。作为站长,你多学习一个软件的使用,意味着你又可以节省一笔服务器开支,例如:

  1. 利用Huginn抓取任意网站RSS和微信公众号更新-打造一站式信息阅读平台
  2. Linux VPS挂载Google Drive和Dropbox-实现VPS主机数据同步备份
  3. 三大免费工具助你检测VPS服务器真伪-VPS主机性能和速度测试方法

PS:2017年10月21日更新,有兴趣使用阿里云香港VPS的朋友可以先看我的评测:阿里云国际版香港机房速度与性能评测-速度快但磁盘IO和内存是瓶颈。如果你还想监控VPS服务器网络的稳定性,可以使用这个工具:Smokeping安装与配置-免费开源网络性能监控工具可视化主/从部署

一、ngxtop安装与使用

1.1  ngxtop安装

项目主页:

  1. https://github.com/lebinh/ngxtop

ngxtop适用于Nginx服务器日志。ngxtop可用如下命令安装:

Fedora:yum install python-pip
CentOS/RHEL需先安装EPEL,安装完后:yum install python-pip
Debian/Ubuntu:apt-get install python-pip

pip install ngxtop

或者也可以直接从源码安装:

wget https://github.com/lebinh/ngxtop/archive/master.zip -O ngxtop-master.zip
unzip ngxtop-master.zip
cd ngxtop-master
python setup.py install

1.2  ngxtop用法

ngxtop的基本用法如下:

gxtop [选项]
ngxtop [选项] (print|top|avg|sum) <变量>
ngxtop info

选项有如下参数:

-l : 指定日志文件的完整路径 (Nginx 或 Apache2)

-f : 日志格式

–no-follow: 处理当前已经写入的日志文件,而不是实时处理新添加到日志文件的日志

-t : 更新频率

-n : 显示行号

-o : 排序规则(默认是访问计数)

-a …, –a …: 添加表达式(一般是聚合表达式如: sum, avg, min, max 等)到输出中。

-v: 输出详细信息

-i : 只处理符合规则的记录

-c <file>或 –config <file> 指定nginx配置文件,自动分析日志格式

-i <filter-expression>或 –filter <filter-expression> 满足表达式的过滤将被处理

-p <filter-expression>或 –pre-filter <filter-expression> in-filter expression to check in pre-parsing phase.

ngxtop的变量有:remote_addr、remote_user、time_local、request、request_path、status、body_bytes_sent、http_referer、http_user_agent。主要是用来分析出IP地址、请求路径、Http状态、referer、user_agent等等。

1.3  ngxtop示例

用ngxtop info可以查看本机的服务器日志地址还有配置文件所在路径,不过,它只能显示一些默认的日志文件,有一些自定义的日志文件不会显示出来。

找出404错误前十的请求URL。命令代码:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow top request_path --filter 'status == 404'

效果如下图:

找出访问数最多的前十个IP地址。命令代码:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow --group-by remote_addr

效果如下图:

找出流量前十的IP地址。命令代码:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow --order-by 'avg(bytes_sent) * count'

找出400错误代码以上的且显示request、status、http_referer三项。命令代码:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow -i 'status >= 400' print request status http_referer

找出bytes_sent平均值且状态码为200且request_path以wzfou开头的前10。命令代码:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow avg bytes_sent --filter 'status == 200 and request_path.startswith("wzfou")'

通过上面几个命令,基本上很快就能锁定一些异常请求的IP地址了。默认的ngxtop会显示前10个记录,你可以加上参数 –n xxx,这样自己控制显示的数量。命令如下:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --no-follow --group-by remote_addr -n 20

ngxtop实现监控服务器日志。要想实时显示Nginx日志监控的情况,只需要去年–no-follow 参数即可,命令如下:

ngxtop -l /data/wwwlogs/wzfou.com_nginx.log --group-by remote_addr

效果如下图:

二、GoAccess安装与使用

2.1  GoAccess安装

GoAccess官网:

  1. https://goaccess.io/

GoAccess支持Apache、Nginx、 Amazon S3、 Elastic Load Balancing、CloudFront等服务器日志的分析。安装命令如下:

apt-get install libncursesw5-dev libgeoip-dev
wget http://tar.goaccess.io/goaccess-1.2.tar.gz
tar -xzvf goaccess-1.2.tar.gz
cd goaccess-1.2/
./configure --enable-utf8 --enable-geoip=legacy
make
make install

根据你自己的需要,你可以在安装GoAccess 调整配置选项。如下:

--enable-debug 使用调试标志编译且关闭编译器优化。
--enable-utf8 宽字符支持。依赖 Ncursesw 模块。
--enable-geoip=<legacy|mmdb> 地理位置支持。依赖 MaxMind GeoIP 模块。 legacy 将使用原始 GeoIP 数据库。 mmdb 将使用增强版 GeoIP2 数据库。
--enable-tcb=<memhash|btree> Tokyo Cabinet 存储支持。 memhash 将使用 Tokyo Cabinet 的内存哈希数据库。btree 将使用 Tokyo Cabinet 的磁盘 B+Tree 数据库。
–disable-zlib 禁止在 B+Tree 数据库上使用 zlib 压缩。
--disable-bzip 禁止在 B+Tree 数据库上使用 bzip2 压缩。
--with-getline 使用动态扩展行缓冲区用来解析完整的行请求,否则将使用固定大小(4096)的缓冲区。
--with-openssl 使 GoAccess 与其 WebSocket 服务器之间的通信能够支持 OpenSSL。

2.2  GoAccess用法

GoAccess语法如下:

goaccess [filename] [ options ... ] [-c][-M][-H][-q][-d][...]

常用的参数说明如下:

-f –log-file=<logfile>

指定输入日志文件的路径。如果在配置文件中指定了输入文件,则其优先级要高于在命令行中通过 -f 参数指定。

-l –log-debug=<filename>

发送所有调试信息到指定文件。需要指定配置选项 --enable-debug

-p –config-file=<configfile>

指定使用自定义配置文件。如果设置了此参数,其优先级将高于全局配置文件(如果有)。

–invalid-requests=<filename>

记录无效请求到指定文件。

–no-global-config

禁止加载全局配置文件。可能的目录应该是 /usr/etc/, /etc/ 或者 /usr/local/etc/, 除非在运行 ./configure 时指定了 --sysconfdir=/dir

-a –agent-list

开启 UserAgent 列表。开启后会降低解析速度。

-d –with-output-resolver

输出 HTML 或者 JSON 报告时开启 IP 解析。

-e –exclude-ip <IP|IP-range>

排除一个 IPv4 或者 IPv6 地址。 使用连接符表示 IP 段(开始-结束)。

-H –http-protocol=<yes|no>

HTTP 请求协议开关。将创建一个请求字段包含请求协议+真实请求。

-M –http-method=<yes|no>

HTTP 请求方法开关。将创建一个请求字段包含请求方法+真实请求。

-o –output=<json|csv>

将给定文件重定向到标准输出,通过后缀名决定输出格式:

-q –no-query-string

忽略请求的查询字符串。即: www.google.com/page.htm?query => www.google.com/page.htm
注意: 去掉查询字符串将极大降低内存消耗,特别对带时间戳的请求。

-r –no-term-resolver

在终端输出时禁止 IP 解析。

–444-as-404

将非标准状态 444 作为 404 处理。

–4xx-to-unique-count

将 4xx 客户端错误数加到独立访客数中。

–all-static-files

统计包含查询字符串的静态文件。

–date-spec=<date|hr>

设置日期的显示格式,一种是标准日期格式(默认),一种是日期后附加小时的格式。
仅在访客面板有效。对于在小时级别分析访客数据很有帮助。显示格式示例:18/Dec/2010:19

–double-decode

解码双重编码的值。包括 UserAgent,Request 以及 Referer。

–enable-panel=<PANEL>

开启指定面板。面板列表:

–hour-spec=<hour|min>

设定时间的显示格式,一种是标准时间格式(默认),一种是时间后附加分钟数(每十分钟)的格式。
用于时间分布面板。对于在特定时间段分析流量峰值很有用处。

–ignore-crawlers

忽略爬虫。

–ignore-panel=<PANEL>

忽略指定面板。面板列表:

–ignore-referer=<referer>

忽略被统计的来路。支持通配符。例如: *.domain.com ww?.domain.*

–ignore-status=<STATUS>

忽略解析或者显示一个或者多个状态码。如果有多个状态码,使用此参数每次指定一个。

–num-tests=<number>

设定测试行数,即使用给定的 日志/日期/时间 格式测试访问日志。默认值为 10 行。如果设置为 0 ,解析器不会做任何测试而是直接解析整个文件。如果在达到 number 之前,有一行匹配上了给定的 日志/日期/时间 格式,则解析器会认为日志文件是有效的,否则 GoAccess 会返回 EXIT_FAILURE 并显示相关的错误信息。

–process-and-exit

解析日志,且退出时不输出数据。主要用于仅希望往磁盘数据库中添加数据而无需输出报告时使用。

–real-os

显示真实的操作系统名称。例如: Windows XP, Snow Leopard.

–sort-panel=<PANEL,FIELD,ORDER>

S在初始化载入是对面板进行排序。排序选项使用逗号分隔。选项使用这样的格式:PANEL,METRIC,ORDER

–static-file <extension>

添加静态文件后缀名。例如:.mp3。 后缀名区分大小写。

-g –std-geoip

标准 GeoIP 数据库,低内存占用。

–geoip-database <geocityfile>

设定 GeoIP 数据库路径。例如:GeoLiteCity.dat。需要从 maxmind.com 上下载到本地。IPv4 和 IPv6 均可用支持。注意:--geoip-city-data--geoip-database 的别名。
注意: 如果使用 GeoIP2,您需要从 MaxMind 下载 城市/国家 数据库,并通过 --geoip-database 设定。

GoAccess日志格式。GoAccess还有一个参数是用来设置服务器日志格式的:–log-format <logformat>。参数 log-format 后跟随一个空格符或者制表分隔符(t),用于指定日志字符串格式。

如果你使用的是下表中的预定义日志格式名称,可以直接当作GoAccess 日志/日期/时间 格式的变量。

COMBINED     | 联合日志格式
VCOMBINED    | 支持虚拟主机的联合日志格式
COMMON       | 通用日志格式
VCOMMON      | 支持虚拟主机的通用日志格式
W3C          | W3C 扩展日志格式
SQUID        | Native Squid 日志格式
CLOUDFRONT   | 亚马逊 CloudFront Web 分布式系统
CLOUDSTORAGE | 谷歌云存储
AWSELB       | 亚马逊弹性负载均衡
AWSS3        | 亚马逊简单存储服务 (S3)

2.3  如何设置日志格式

首先看看你的log_format是什么,log_format指令如下:

语法: log_format name string …;
默认值: log_format combined “…”;
配置段: http

name表示格式名称,string表示等义的格式。log_format有一个默认的无需设置的combined日志格式,相当于apache的combined日志格式,如下所示:

log_format  combined  '$remote_addr - $remote_user  [$time_local]  '
                                   ' "$request"  $status  $body_bytes_sent  '
                                   ' "$http_referer"  "$http_user_agent" ';

当然,你也可以根据自己的需要来添加服务器日志需要获取的信息。以下是日志格式允许包含的变量:

remote_addr, $http_x_forwarded_for 记录客户端IP地址
remote_user 记录客户端用户名称
request 记录请求的URL和HTTP协议
status 记录请求状态
body_bytes_sent 发送给客户端的字节数,不包括响应头的大小; 该变量与Apache模块mod_log_config里的“%B”参数兼容。
bytes_sent 发送给客户端的总字节数。
connection 连接的序列号。
connection_requests 当前通过一个连接获得的请求数量。
msec 日志写入时间。单位为秒,精度是毫秒。
pipe 如果请求是通过HTTP流水线(pipelined)发送,pipe值为“p”,否则为“.”。
http_referer 记录从哪个页面链接访问过来的
http_user_agent 记录客户端浏览器相关信息
request_length 请求的长度(包括请求行,请求头和请求正文)。
request_time 请求处理时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
time_iso8601 ISO8601标准格式下的本地时间。
time_local 通用日志格式下的本地时间。

以下是log_format设置实例:

http {
 log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                                        '"$status" $body_bytes_sent "$http_referer" '
                                        '"$http_user_agent" "$http_x_forwarded_for" '
                                        '"$gzip_ratio" $request_time $bytes_sent $request_length';
 
 log_format srcache_log '$remote_addr - $remote_user [$time_local] "$request" '
                                '"$status" $body_bytes_sent $request_time $bytes_sent $request_length '
                                '[$upstream_response_time] [$srcache_fetch_status] [$srcache_store_status] [$srcache_expire]';
 
 open_log_file_cache max=1000 inactive=60s;
 
 server {
 server_name ~^(www.)?(.+)$;
 access_log logs/$2-access.log main;
 error_log logs/$2-error.log;
 
 location /srcache {
 access_log logs/access-srcache.log srcache_log;
 }
 }
}

这是GoAccess日志格式与服务器log-format对应关系:

%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 请求所花费的时间,单位秒

%^ 忽略这一字段

GoAccess日志修改示例:

log_format access '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $http_x_forwarded_for $request_time $upstream_response_time';

GoAccess默认的配置文件goaccess.conf放置于/usr/local/etc路径中,默认的格式是:log-format %h %^[%d:%t %^] "%r" %s %b "%R" "%u"。观察上面的服务器日志格式,发现多了响应时间$request_time和upstream的响应时间$upstream_response_time。

我们可以修改如下:

原来:log-format %h %^[%d:%t %^] "%r" %s %b "%R" "%u"
修改:log-format %h %^[%d:%t %^] "%r" %s %b "%R" "%u" %^ %^ %T

最后三个元素%^ %^ %T%^表示忽略,%T表示“以秒为单位的响应时间,精确到毫秒”。通过修改GoAccess的格式就与我们的服务器日志格式对应上了。

2.4  GoAccess示例

如果你的服务器用的是通用日志格式,联合日志格式,包含虚拟主机,W3C 格式以及亚马逊 CloudFront(分布式下载)等,就不需要修改日志格式,直接使用即可。LNMPOneinstack都是用的COMBINED格式。

GoAccess在终端在分析日志命令:

goaccess -d -f /data/wwwlogs/wzfou.com_nginx.log --log-format=COMBINED

以上命令中,-f 指定要分析的日志/path/to/log;–log-format 日志的格式,LNMP默认格式为:COMBINED。运行后效果如下图:

操作热键如下:

F1h主帮助页面。

F5重绘主窗口。

q退出程序,当前窗口或者崩溃了的模块。

oENTER扩展选中的模块或打开窗口。

0-9Shift + 0激活选中的模块。

j在已扩展模块中向下滚动。

k在已扩展模块中向上滚动。

c设置或者改变配色方案。

^ f在当前模块中向前滚动一屏。

^ b在当前模块中向后滚动一屏。

TAB切换模块(向前)。

SHIFT + TAB切换模块(向后)。

s给活跃模块的选项排序。

/在所有模块中搜索(支持正则)。

n找到下次发生事件的位置。

g移动到第一个选项或者屏幕顶部。

G移动到第最后一个选项或者屏幕底部。

如果你想要查看访问数前十的IP地址,按下数字键5,就可以打开该模块详情了。如下图:

其它的几个数字对应模块如下:

按 1 定位到“按天访问量”

按 2 定位到“最多次被请求的 URL”

按 3 定位到“最多次被请求的静态文件”

按 4 定位到“最多次被请求的 404”

按 5 定位到“最多次请求的用户 IP”

按 6 定位到“用户的操作系统”

按 7 定位到“用户的浏览器”

按 8 定位到“按小时的统计”

GoAccess输出。 命令如下:

生成一份 HTML 报告:

# goaccess access.log -a -o report.html

生成一份 JSON 报告:

# goaccess access.log -a -d -o report.json

生成一份 CSV 文件:

# goaccess access.log --no-csv-summary -o report.csv

GGoAccess 非常灵活,支持实时解析和过滤。例如:需要通过监控实时日志来快速诊断问题:

# tail -f access.log | goaccess -

更厉害的是,还可以使用 tail -f 和一个模式匹配工具一起工作,比如: grep, awk, sed 等等

# tail -f access.log | grep -i --line-buffered 'firefox' | goaccess --log-format=COMBINED -

又或者可以在管道打开的状态下从头开始解析文件,并同时应用一个过滤器:

# tail -f -n +0 access.log | grep --line-buffered 'Firefox' | goaccess -o out.html --real-time-html -

例如:

将GoAccess输出Html,然后用浏览器访问,可用以下命令:

goaccess -d -f /data/wwwlogs/wzfou.com_nginx.log --log-format=COMBINED -a > /data/wwwroot/howsvps.com/wzfou.html

用浏览器访问效果如下图(点击放大):

GoAccess输出的图表非常漂亮,你还可在图表中查看详细的选项。详情还可以看看官网的Demo:https://rt.goaccess.io/

将GoAccess输出Html并实时刷新,命令如下:

goaccess -d -f /data/wwwlogs/howsvps.com_nginx.log --log-format=COMBINED -a > /data/wwwroot/howsvps.com/wzfou.html --real-time-html --port=9870 --daemonize

以上是守护进程启动 GoAccess 后,使用 Websocket 建立长连接,它默认监听 7890 端口,可以通过--port参数指定端口号。

指定端口号后,记得在你的VPS防火墙中打开:

iptables -A INPUT -p tcp -m tcp --dport 9870 -j ACCEPT

三、总结

ngxtop适合简单的查找需要,GoAccess偏重于整体分析,甚至可以当成统计使用。如果你的网站使用的SSL,那么在GoAccess输出实时监控的HTML页面时,记得在在配置文件goaccess.conf中配置ssl-certssl-key项。

当然,我们也可以使用crontab定时让GoAccess生成统计html页面,这样也相当于实时在线监控服务器日志了。代码如下(每5分钟生成一次HtmL页面):

*/5 * * * * goaccess -d -f /data/wwwlogs/wzfou.com_nginx.log --log-format=COMBINED -a > /data/wwwroot/wzfou.com/wzfou.html

对于不知道如何设置GoAccess日志格式的朋友,你可以直接使用在线转换工具:https://github.com/stockrt/nginx2goaccess。命令:

用法: ./nginx2goaccess.sh '<log_format>'

./nginx2goaccess.sh '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"'

输出的结果你就可以直接用在GoAccess日志格式设置中了:

- Generated goaccess config:

time-format %T
date-format %d/%b/%Y
log_format %h - %^ [%d:%t %^] "%r" %s %b "%R" "%u"

发表评论