用awk统计404和5xx频次最简捷:awk '$9 ~ /^404$|^5[0-9]{2}$/ {count[$9]++} END {for (code in count) print code, count[code]}' access.log,需确认第9列为状态码,自定义格式时先校验字段;实时监控改用tail -f | awk '/404|5[0-9][0-9]/ {print $9, $7}' | sort | uniq -c | sort -nr;高频URL路径用grep ' 404 ' | cut -d" " -f7或awk -F'"' '{print $2}' | awk '{print $2}'提取;5xx需交叉比对access.log与error.log时间戳定位真实原因。

用awk快速统计404和5xx出现频次
直接在日志文件上跑命令最省事,不用动配置、不依赖额外工具。Apache默认日志格式里状态码是第9个字段(以空格分隔),awk按列过滤最稳:
awk '$9 ~ /^404$|^5[0-9]{2}$/ {count[$9]++} END {for (code in count) print code, count[code]}' /var/log/apache2/access.log
注意点:
-
/^404$|^5[0-9]{2}$/严格匹配完整状态码,避免把4040或5001这类非标准值误算进去 - 如果日志用了自定义格式(比如加了
%D或%{X-Forwarded-For}i),字段序号可能变化,先用head -1 /var/log/apache2/access.log | awk '{print NF; print $1,$2,$9}'确认第9列确实是状态码 - 实时监控时加
tail -f会卡住END块,得换用awk '/404|5[0-9][0-9]/ {print $9, $7}' | sort | uniq -c | sort -nr
用grep + cut组合定位高频URL路径
光知道状态码多没用,得看是哪些URL在反复失败。404通常指向缺失资源,5xx大概率是后端服务崩了,路径特征完全不同:
grep ' 404 ' /var/log/apache2/access.log | cut -d' ' -f7 | sort | uniq -c | sort -nr | head -20
grep ' 5[0-9][0-9] ' /var/log/apache2/access.log | cut -d' ' -f7 | sort | uniq -c | sort -nr | head -20
关键细节:
-
cut -d' ' -f7提取请求路径(第7字段),但前提是日志没启用双引号包裹——如果看到"GET /api/v1/user HTTP/1.1"这种格式,得改用awk -F'"' '{print $2}' | awk '{print $2}' - 5xx结果里如果大量出现
/health或/readyz,基本可判定上游服务已不可用;404里若集中于/static/js/xxx.min.js,优先查构建产物是否漏传 - 别忽略时间维度:加
awk '$4 ~ /\[.*\/Mar\/2024/限定某天,避免被历史噪音干扰
用Logstash或rsyslog做实时告警的取舍
人工查日志只能救火,真要盯异常得上实时链路。但Logstash太重,小项目用rsyslog更轻量:
在 /etc/rsyslog.d/10-apache-error.conf 里加:
if $programname == 'apache2' and ($msg contains ' 404 ' or $msg contains ' 500 ' or $msg contains ' 502 ' or $msg contains ' 503 ') then /var/log/apache_alerts.log & stop
然后用 inotifywait -m /var/log/apache_alerts.log -e modify | while read ... 触发钉钉/企微通知。注意:
- rsyslog默认只收error.log,access.log得先用
logger -t apache2 -p local6.info手动转发,否则规则不生效 - Logstash适合已有ELK栈的场景,但
grok对Apache日志的正则必须匹配你实际的LogFormat,比如用了%{COMMONAPACHELOG}却少了%{IPORHOST:clientip}字段,整个pipeline会丢数据 - 所有实时方案都绕不开日志轮转问题:
logrotate切文件时,rsyslog可能短暂丢失事件,加copytruncate或用systemd-journald对接更稳
排查5xx时必须交叉验证access.log和error.log
access.log里的5xx只是“Apache返回给客户端的结果”,不等于后端真挂了——可能是代理超时、SSL握手失败、甚至mod_security拦截后伪造的503。这时候单看access.log会误判:
- 拿一个502的时间戳(比如
[15/Mar/2024:14:22:33),去error.log里搜14:22:3[0-9],看有没有Connection refused或upstream timed out - 如果error.log完全安静,再查
ssl_error_log(如果有启用SSL),500可能是SSL_read() failed这类底层错误 - 某些CDN回源失败也会打5xx到access.log,但Apache自身error.log无记录——这时得翻CDN后台的原始日志,不能只信本地日志
真正难搞的是500混着Python traceback又没开LogLevel debug,或者PHP-FPM子进程静默崩溃,这种必须配合strace -p $(pgrep php-fpm)抓系统调用才能定位。










