7.6.3 日志分析与可视化(goaccess/ELK)

在日志分析与可视化方面,Nginx常用两条路线:轻量快速分析的 GoAccess 与集中化检索分析的 ELK(Elasticsearch/Logstash/Kibana)。前者适合单机或小规模,后者适合多节点、跨业务、长期留存与告警联动的场景。核心目标是把“访问日志与错误日志”转化为可查询指标、可视化报表与问题定位依据。

原理草图(采集→解析→存储→可视化):

文章图片

一、Nginx日志格式准备(GoAccess/ELK通用)

# /etc/nginx/nginx.conf
http {
    log_format ops '$remote_addr - $remote_user [$time_local] '
                   '"$request" $status $body_bytes_sent '
                   '"$http_referer" "$http_user_agent" '
                   'rt=$request_time urt=$upstream_response_time '
                   'ua="$upstream_addr" rid=$request_id';

    access_log /var/log/nginx/access.log ops;
    error_log  /var/log/nginx/error.log warn;
}

说明:
- rturt 用于慢请求定位;rid 便于跨系统追踪;字段稳定是解析成功的关键。

二、GoAccess:快速分析与实时页面
1) 安装(以 Ubuntu 为例)

sudo apt-get update
sudo apt-get install -y goaccess
goaccess --version

2) 解析访问日志(离线报表)

# 生成静态HTML报表
goaccess /var/log/nginx/access.log \
  --log-format='%h - %u [%d:%t %^] "%r" %s %b "%R" "%u" rt=%T urt=%^ ua="%^" rid=%^' \
  --date-format='%d/%b/%Y' \
  --time-format='%H:%M:%S' \
  -o /var/www/html/report.html

关键参数说明:
- --log-format 必须与 Nginx log_format 一致;%^ 表示跳过不需字段
- -o 输出HTML到Web目录,浏览器打开即可

3) 实时监控页

goaccess /var/log/nginx/access.log \
  --log-format='%h - %u [%d:%t %^] "%r" %s %b "%R" "%u" rt=%T urt=%^ ua="%^" rid=%^' \
  --date-format='%d/%b/%Y' \
  --time-format='%H:%M:%S' \
  --real-time-html \
  -o /var/www/html/realtime.html

预期效果:实时看到请求量、状态码分布、慢请求、TOP URL。

常见排错:
- 报“Invalid log format”:核对 Nginx log_format 与 GoAccess --log-format 是否一致
- 时间字段解析失败:检查 time_local 是否包含时区,必要时用 %^ 跳过
- 实时页无数据:确保访问日志持续写入,且文件权限可读

三、ELK:集中化检索与可视化
1) 组件与流程示意

文章图片

2) Filebeat 安装与采集配置

sudo apt-get install -y filebeat
sudo tee /etc/filebeat/filebeat.yml >/dev/null <<'EOF'
filebeat.inputs:
  - type: log
    enabled: true
    paths:
      - /var/log/nginx/access.log
    fields:
      service: nginx
    fields_under_root: true

output.logstash:
  hosts: ["127.0.0.1:5044"]
EOF

sudo systemctl enable --now filebeat
sudo systemctl status filebeat --no-pager

3) Logstash 解析配置(基于上述 log_format)

# /etc/logstash/conf.d/nginx.conf
input {
  beats { port => 5044 }
}

filter {
  grok {
    match => {
      "message" => '%{IPORHOST:remote_addr} - %{DATA:remote_user} \[%{HTTPDATE:time_local}\] "%{WORD:request_method} %{DATA:uri} HTTP/%{NUMBER:http_version}" %{NUMBER:status:int} %{NUMBER:body_bytes_sent:int} "%{DATA:http_referer}" "%{DATA:http_user_agent}" rt=%{NUMBER:request_time:float} urt=%{DATA:upstream_response_time} ua="%{DATA:upstream_addr}" rid=%{DATA:request_id}'
    }
  }
  date {
    match => [ "time_local", "dd/MMM/yyyy:HH:mm:ss Z" ]
    target => "@timestamp"
  }
}

output {
  elasticsearch {
    hosts => ["http://127.0.0.1:9200"]
    index => "nginx-%{+YYYY.MM.dd}"
  }
}

启动与检查:

sudo systemctl enable --now logstash
sudo systemctl status logstash --no-pager

4) Elasticsearch 健康检查

curl -s http://127.0.0.1:9200/_cluster/health?pretty

5) Kibana 基础可视化建议
- 指标:QPS、状态码分布、P95/P99 请求时间、上游失败率、TOP URL
- 过滤:status:[500 TO 599] 定位服务端异常
- 对比:按 servicehost 维度拆分

常见排错:
- Kibana无数据:检查 Logstash 输出索引名与 Kibana Index Pattern 是否一致
- grok解析失败:到 Logstash 日志中查看 _grokparsefailure,调试正则或 log_format
- 高基数字段:http_user_agent 字段建议做分词/截断或仅保留解析后版本

四、关键命令与效果速查

# 统计近1分钟的访问量(快速命令)
tail -n 2000 /var/log/nginx/access.log | awk '{print $4}' | uniq -c | tail

# 统计5xx错误
awk '$9 ~ /^5/ {count++} END{print "5xx:",count}' /var/log/nginx/access.log

# 查找超时上游
awk '$0 ~ /urt=/ {print $0}' /var/log/nginx/access.log | grep 'urt=-' | head

五、练习
1) 练习1:为 Nginx 增加 request_id 字段并验证 GoAccess 正确解析
目标:打开 report.html 可看到“请求数/状态码/慢请求”报表。

2) 练习2:在 Logstash 中新增字段 is_slowrequest_time > 1)并在 Kibana 过滤
目标:创建“慢请求趋势图”,观察高峰时段。

3) 练习3:模拟 500 错误并在 Kibana 快速定位
方法:临时配置一个返回 500 的 location,刷新后在 Kibana 通过 status:500 过滤。