igozhang

——

    nginx 问题诊断

    1. 定位 nginx 日志位置与规则

    sudo bash <<'EOF'
    TMP=$(mktemp)
    trap 'rm -f "$TMP"' EXIT
    nginx -T >"$TMP" 2>/dev/null
    
    echo "=== compile-time default log paths ==="
    DEF=$(nginx -V 2>&1 | grep -oE -- '--(error-log-path|http-log-path)=[^ ]+' || true)
    if [ -n "$DEF" ]; then printf '%s\n' "$DEF"
    else echo "(not in nginx -V)"; DEF="--error-log-path=/var/log/nginx/error.log"
    fi
    
    echo ""
    echo "=== log rules from nginx -T ==="
    awk '
      /^[[:space:]]*log_format[[:space:]]/ {p=1}
      p {print; if (/;/) p=0; next}
      /^[[:space:]]*(error_log|access_log)[[:space:]]/ {print}
    ' "$TMP"
    grep -qE '^[[:space:]]*error_log[[:space:]]' "$TMP" \
      || echo "(no error_log directive; use compile-time default)"
    
    echo ""
    echo "=== log files ==="
    {
      printf '%s\n' "$DEF" | cut -d= -f2-
      awk '/^[[:space:]]*(error_log|access_log)[[:space:]]/ {
        gsub(/;/,"",$2)
        if ($2!="" && $2!="off" && $2!~/^syslog:/) print $2
      }' "$TMP"
    } | sed '/^$/d' | sort -u | while read -r f; do
      ls -lh "$f" 2>/dev/null || echo "MISSING $f"
    done
    EOF
    

    2. 筛选 access log 最近 2 小时常见报错

    默认路径在命令末尾;若为空自动尝试 .1 与 /etc/nginx/logs/access.log。时间窗按日志末行往前约 2 小时(避免轮转后按“当前时刻”筛空)。

    sudo bash -s -- /var/log/nginx/access.log <<'EOF'
    CAND=$1
    LOG=
    for f in "$CAND" "${CAND}.1" /etc/nginx/logs/access.log /var/log/nginx/access.log.1; do
      [ -s "$f" ] && [ -r "$f" ] && LOG=$f && break
    done
    [ -n "$LOG" ] || LOG=$CAND
    echo "=== log: $LOG (cand=$CAND) ==="
    [ -r "$LOG" ] && [ -s "$LOG" ] || { echo "log missing or empty"; exit 1; }
    
    RAW=$(tail -n 1 "$LOG" | grep -oE '[0-9]{2}/[A-Za-z]{3}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2}' | tail -n 1)
    [ -n "$RAW" ] || { echo "no timestamp in last line"; exit 1; }
    DAY=${RAW%%/*}; R1=${RAW#*/}; MON=${R1%%/*}; R2=${R1#*/}; YEAR=${R2%%:*}; HMS=${R2#*:}
    EPOCH=$(date -d "$DAY $MON $YEAR $HMS" +%s)
    H0=$(date -d "@$EPOCH" +%d/%b/%Y:%H)
    H1=$(date -d "@$((EPOCH-3600))" +%d/%b/%Y:%H)
    H2=$(date -d "@$((EPOCH-7200))" +%d/%b/%Y:%H)
    echo "=== window by log end: $H2 $H1 $H0 (last=$RAW) ==="
    [ "$(( $(date +%s) - EPOCH ))" -gt 7200 ] && echo "NOTE: log end older than 2h wall clock"
    
    TMP=$(mktemp); DIR=$(mktemp -d)
    trap 'rm -f "$TMP"; rm -rf "$DIR"' EXIT
    tail -n 300000 "$LOG" | grep -E "\[($H2|$H1|$H0):" >"$TMP"
    echo "=== matched lines: $(wc -l <"$TMP") ==="
    
    echo ""
    echo "=== status counts ==="
    sed -nE 's/.*"[A-Z]+ [^"]*" ([0-9]{3}) .*/\1/p' "$TMP" | sort | uniq -c | sort -rn | head -n 20
    
    for code in 499 404 504 502 500 403 401 408 429; do
      ( sed -nE "s/.*\"[A-Z]+ ([^ \"?]+)[^\"]*\" $code .*/\1/p" "$TMP" \
          | sort | uniq -c | sort -rn | head -n 15 >"$DIR/$code" ) &
    done
    wait
    for code in 499 404 504 502 500 403 401 408 429; do
      echo ""
      echo "=== HTTP $code top URIs ==="
      cat "$DIR/$code"
    done
    EOF
    

    常见状态码说明

    状态码 说明
    499 客户端在服务端响应完成前断开(超时、取消请求、上游过慢)
    404 资源不存在(路径错误、静态文件缺失、路由未配置)
    504 网关超时(等上游超时,查 proxy_read_timeout 与后端耗时)
    502 坏网关(上游不可达、进程退出、端口/协议错误)
    500 服务端内部错误(应用异常或后端处理失败)
    403 禁止访问(权限、deny、目录浏览关闭等)
    401 未认证(登录/Auth/Token 缺失或无效)
    408 请求超时(客户端发送过慢或空闲超时)
    429 请求过多(限流或防刷触发)

    MP3