开发工具

如何监测 Nginx 访问日志 502 情况,并做相应动作?

以下是一个用于监测Nginx访问日志中502状态码(Bad Gateway)的Shell脚本,当检测到指定阈值时触发告警或自动恢复操作,并提供详细注释和扩展建议:

脚本功能

1、实时监控Nginx访问日志中的502错误
2、支持自定义检测阈值(例如:1分钟内出现5次502则告警)
3、触发动作:邮件通知、服务重启、自定义恢复脚本
4、自动记录检测结果到日志文件


脚本代码

#!/bin/bash
# Nginx 502错误监控脚本

# 配置参数
LOG_FILE="/var/log/nginx/access.log"  # Nginx日志路径
ERROR_CODE="502"                     # 监控的状态码
THRESHOLD=5                          # 触发动作的阈值(次数)
TIME_WINDOW=60                       # 检测时间窗口(秒)
ALERT_EMAIL="admin@example.com"      # 告警通知邮箱
NGINX_RESTART_CMD="systemctl restart nginx"  # Nginx重启命令

# 临时存储检测结果
TMP_FILE="/tmp/nginx_502_monitor.tmp"

# 日志记录函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> /var/log/nginx_502_monitor.log
}

# 核心检测逻辑
detect_502() {
    # 获取最近TIME_WINDOW秒内的502错误数量
    count=$(tail -n 1000 "$LOG_FILE" | awk -v code="$ERROR_CODE" -v now=$(date +%s) '
    {
        # 解析日志时间(假设日志时间格式为[05/Oct/2023:14:30:22 +0800])
        gsub(/\[/, "", $4);
        timestamp = mktime(gensub(":", " ", "g", substr($4, 1, 20)));
        if (now - timestamp <= '$TIME_WINDOW' && $9 == code) {
            count++
        }
    } END { print count }'
    )

    # 判断是否超过阈值
    if [ "$count" -ge "$THRESHOLD" ]; then
        log "检测到502错误次数: $count (阈值: $THRESHOLD)"
        return 0  # 满足条件
    else
        return 1  # 未满足条件
    fi
}

# 触发动作
take_action() {
    # 1. 发送邮件告警
    echo "Nginx 502错误告警:
    - 时间: $(date)
    - 错误次数: $count
    - 日志片段:
    $(grep " $ERROR_CODE " "$LOG_FILE" | tail -n 3)" | mail -s "Nginx 502告警" "$ALERT_EMAIL"

    # 2. 自动重启Nginx(可选)
    # $NGINX_RESTART_CMD && log "Nginx已重启"

    # 3. 执行自定义恢复脚本(示例)
    # /path/to/recovery_script.sh
}

# 主循环(实时监控模式)
monitor() {
    log "开始监控502错误..."
    tail -F "$LOG_FILE" | while read line; do
        if echo "$line" | awk '$9 == '"$ERROR_CODE"' { exit 0 }'; then
            echo "$line" >> "$TMP_FILE"
            current_count=$(wc -l < "$TMP_FILE")
            if [ "$current_count" -ge "$THRESHOLD" ]; then
                take_action
                > "$TMP_FILE"  # 清空临时计数器
                sleep 300      # 冷却时间(避免重复告警)
            fi
        fi
    done
}

# 执行检测(定期模式)
# 使用crontab每1分钟运行一次:*/1 * * * * /path/to/script.sh
periodic_check() {
    if detect_502; then
        take_action
    fi
}

# 选择模式:实时监控(monitor)或定期检测(periodic_check)
# monitor
periodic_check


使用说明

1、配置参数

修改 LOG_FILE 为你的Nginx访问日志路径

调整 THRESHOLD 和 TIME_WINDOW 设置触发阈值(例如:60秒内5次502错误)

填写 ALERT_EMAIL 接收告警的邮箱


2、运行模式

实时监控:执行 monitor 函数(需手动运行脚本或配置为后台服务)

定期检测:执行 periodic_check 函数并通过crontab定时运行(推荐)


3、部署到crontab

# 每5分钟检测一次
*/5 * * * * /path/to/script.sh



扩展功能

1、多日志文件支持

监控多个日志文件(如多个虚拟主机):

LOG_FILES=("/var/log/nginx/host1.access.log" "/var/log/nginx/host2.access.log")
for log in "${LOG_FILES[@]}"; do
    count+=$(分析逻辑)
done


2、集成告警平台

替换邮件通知为钉钉/企业微信机器人:

# 钉钉机器人示例
DING_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=xxx"
curl -s "$DING_WEBHOOK" -H 'Content-Type: application/json' -d "{
    'msgtype': 'text',
    'text': {'content': 'Nginx 502告警: 错误次数 $count'}
}"


3、自动故障转移

当持续出现502时,切换上游服务器:

# 修改Nginx配置中的上游服务器
sed -i 's/server bad-backend:80/server good-backend:80/' /etc/nginx/upstream.conf
nginx -s reload



注意事项

1、日志时间格式

脚本假设日志时间格式为 [05/Oct/2023:14:30:22 +0800],如使用其他格式需调整 gensub 部分。


2、性能优化

对于高流量网站,避免使用 tail -F 实时监控,改用定期分析。

使用 logrotate 管理日志文件大小。


3、权限配置

确保脚本有权限读取Nginx日志文件。

若需要重启服务,配置sudo权限:

# 在/etc/sudoers中添加
your_user ALL=(ALL) NOPASSWD: /bin/systemctl restart nginx


4、测试验证

手动生成502错误测试脚本:

# 快速生成测试日志(需临时修改Nginx返回502)
echo '127.0.0.1 - - [05/Oct/2023:15:00:00 +0800] "GET / HTTP/1.1" 502 572 "-" "curl/7.68.0"' >> $LOG_FILE


通过此脚本,您可以快速搭建Nginx 502错误监控系统,及时发现问题并触发告警或自动恢复,保障服务可用性。