Nginx 日志配置与管理

Logging Configuration and Management

概述

日志是监控Nginx服务器状态、分析访问模式、调试问题和安全审计的重要工具。Nginx提供了灵活的日志配置选项,包括访问日志、错误日志和自定义日志格式。本文将详细介绍Nginx日志系统的配置和管理方法。

1. 日志类型和基础概念

1.1 日志类型

Nginx日志类型:
├── 访问日志 (Access Log)
│   ├── HTTP请求记录
│   ├── 响应状态码
│   └── 请求处理时间
├── 错误日志 (Error Log)
│   ├── 系统错误
│   ├── 配置错误
│   └── 运行时错误
└── 自定义日志
    ├── 安全日志
    ├── 性能日志
    └── 业务日志

1.2 日志级别

# 错误日志级别(从高到低)
debug    # 调试信息(最详细)
info     # 信息性消息
notice   # 通知信息
warn     # 警告信息
error    # 错误信息
crit     # 严重错误
alert    # 需要立即处理的警报
emerg    # 系统不可用(最严重)

2. 访问日志配置

2.1 基本访问日志配置

http {
    # 默认日志格式
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                   '$status $body_bytes_sent "$http_referer" '
                   '"$http_user_agent" "$http_x_forwarded_for"';

    # 全局访问日志
    access_log /var/log/nginx/access.log main;

    server {
        listen 80;
        server_name example.com;

        # 服务器级别的访问日志
        access_log /var/log/nginx/example.com.access.log main;

        location /api {
            # 位置级别的访问日志
            access_log /var/log/nginx/api.access.log main;
        }

        location /static {
            # 禁用访问日志
            access_log off;
        }
    }
}

2.2 自定义日志格式

http {
    # 详细的访问日志格式
    log_format detailed '$remote_addr - $remote_user [$time_local] '
                       '"$request" $status $body_bytes_sent '
                       '"$http_referer" "$http_user_agent" '
                       '$request_time $upstream_response_time '
                       '$upstream_addr $upstream_status '
                       '"$http_x_forwarded_for" "$http_x_real_ip"';

    # JSON格式日志
    log_format json escape=json '{'
                               '"timestamp":"$time_iso8601",'
                               '"remote_addr":"$remote_addr",'
                               '"remote_user":"$remote_user",'
                               '"request":"$request",'
                               '"status":$status,'
                               '"body_bytes_sent":$body_bytes_sent,'
                               '"http_referer":"$http_referer",'
                               '"http_user_agent":"$http_user_agent",'
                               '"request_time":$request_time,'
                               '"upstream_response_time":"$upstream_response_time"'
                               '}';

    # 性能监控日志格式
    log_format performance '$remote_addr [$time_local] "$request" '
                          '$status $body_bytes_sent '
                          'rt=$request_time '
                          'urt=$upstream_response_time '
                          'cs=$upstream_cache_status';

    # 安全日志格式
    log_format security '$remote_addr [$time_local] "$request" '
                       '$status "$http_user_agent" '
                       '"$http_x_forwarded_for" $request_length '
                       '$request_time $connection $connection_requests';
}

2.3 条件日志记录

http {
    # 定义条件变量
    map $status $log_condition {
        ~^[23] 0;  # 2xx和3xx状态码不记录
        default 1;  # 其他状态码记录
    }

    map $request_uri $skip_log {
        ~*\.(js|css|png|jpg|jpeg|gif|ico|svg)$ 0;
        default 1;
    }

    server {
        listen 80;
        server_name example.com;

        # 条件日志记录 - 只记录错误
        access_log /var/log/nginx/error_only.log main if=$log_condition;

        # 条件日志记录 - 跳过静态文件
        access_log /var/log/nginx/dynamic_only.log main if=$skip_log;

        location /admin {
            # 管理区域完整日志
            access_log /var/log/nginx/admin.log detailed;
        }
    }
}

3. 错误日志配置

3.1 基本错误日志配置

# 全局错误日志
error_log /var/log/nginx/error.log warn;

http {
    # HTTP级别错误日志
    error_log /var/log/nginx/http_error.log;

    server {
        listen 80;
        server_name example.com;

        # 服务器级别错误日志
        error_log /var/log/nginx/example.com.error.log;

        location /api {
            # 位置级别错误日志
            error_log /var/log/nginx/api_error.log debug;
        }
    }
}

3.2 调试日志配置

# 开启调试日志(需要编译时支持)
error_log /var/log/nginx/debug.log debug;

events {
    # 调试特定连接
    debug_connection 192.168.1.100;
    debug_connection 2001:db8::/32;
}

http {
    server {
        listen 80;
        server_name debug.example.com;

        # 调试特定服务器
        error_log /var/log/nginx/debug_server.log debug;

        location /debug {
            # 输出调试信息到响应
            add_header X-Debug-Info "Request processed";
            return 200 "Debug mode enabled\n";
        }
    }
}

4. 日志轮转配置

4.1 使用logrotate进行日志轮转

# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily                   # 每天轮转
    missingok              # 文件不存在不报错
    rotate 52              # 保留52个文件
    compress               # 压缩旧文件
    delaycompress          # 延迟压缩
    notifempty             # 空文件不轮转
    create 0640 nginx nginx # 创建新文件的权限
    sharedscripts          # 共享脚本
    prerotate
        if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
            run-parts /etc/logrotate.d/httpd-prerotate; \
        fi \
    endscript
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 `cat /var/run/nginx.pid`
        fi
    endscript
}

4.2 自定义日志轮转脚本

#!/bin/bash
# /usr/local/bin/nginx-log-rotate.sh

LOG_DIR="/var/log/nginx"
BACKUP_DIR="/var/log/nginx/backup"
DATE=$(date +%Y%m%d)

# 创建备份目录
mkdir -p $BACKUP_DIR

# 移动当前日志文件
for log_file in $LOG_DIR/*.log; do
    if [ -f "$log_file" ]; then
        filename=$(basename "$log_file")
        mv "$log_file" "$BACKUP_DIR/${filename}-${DATE}"
    fi
done

# 发送USR1信号给nginx重新打开日志文件
if [ -f /var/run/nginx.pid ]; then
    kill -USR1 $(cat /var/run/nginx.pid)
fi

# 压缩7天前的日志
find $BACKUP_DIR -name "*.log-*" -type f -mtime +7 -exec gzip {} \;

# 删除30天前的压缩日志
find $BACKUP_DIR -name "*.gz" -type f -mtime +30 -delete

echo "Log rotation completed at $(date)"

4.3 定时任务设置

# 添加到crontab
crontab -e

# 每天凌晨2点执行日志轮转
0 2 * * * /usr/local/bin/nginx-log-rotate.sh >> /var/log/log-rotate.log 2>&1

5. 日志分析和监控

5.1 实时日志监控

# 实时查看访问日志
tail -f /var/log/nginx/access.log

# 实时查看错误日志
tail -f /var/log/nginx/error.log

# 过滤特定状态码
tail -f /var/log/nginx/access.log | grep " 404 "

# 监控多个日志文件
multitail /var/log/nginx/access.log /var/log/nginx/error.log

5.2 日志分析脚本

#!/bin/bash
# nginx-log-analyzer.sh

LOG_FILE=${1:-/var/log/nginx/access.log}

echo "=== Nginx访问日志分析 ==="
echo "日志文件: $LOG_FILE"
echo "分析时间: $(date)"
echo

# 总请求数
total_requests=$(wc -l < $LOG_FILE)
echo "总请求数: $total_requests"

# 独立访客数(基于IP)
unique_visitors=$(awk '{print $1}' $LOG_FILE | sort | uniq | wc -l)
echo "独立访客: $unique_visitors"

# 最多访问的IP
echo -e "\n=== 访问最多的IP ==="
awk '{print $1}' $LOG_FILE | sort | uniq -c | sort -nr | head -10

# 最多访问的页面
echo -e "\n=== 访问最多的页面 ==="
awk '{print $7}' $LOG_FILE | sort | uniq -c | sort -nr | head -10

# 状态码统计
echo -e "\n=== HTTP状态码统计 ==="
awk '{print $9}' $LOG_FILE | sort | uniq -c | sort -nr

# 浏览器统计
echo -e "\n=== 浏览器统计 ==="
awk -F'"' '{print $6}' $LOG_FILE | sort | uniq -c | sort -nr | head -10

# 小时访问量统计
echo -e "\n=== 小时访问量统计 ==="
awk '{print $4}' $LOG_FILE | cut -c 14-15 | sort | uniq -c

5.3 使用GoAccess进行可视化分析

# 安装GoAccess
sudo apt install goaccess  # Ubuntu/Debian
sudo yum install goaccess  # CentOS/RHEL

# 生成HTML报告
goaccess /var/log/nginx/access.log -o /var/www/html/report.html --log-format=COMBINED

# 实时监控
goaccess /var/log/nginx/access.log -o /var/www/html/report.html --log-format=COMBINED --real-time-html

# 自定义日志格式
goaccess /var/log/nginx/access.log \
    --log-format='%h %^[%d:%t %^] "%r" %s %b "%R" "%u"' \
    --date-format='%d/%b/%Y' \
    --time-format='%T' \
    -o report.html

6. 性能优化

6.1 日志缓冲配置

http {
    # 访问日志缓冲
    access_log /var/log/nginx/access.log main buffer=64k flush=5s;

    # 错误日志缓冲
    error_log /var/log/nginx/error.log warn;

    server {
        listen 80;
        server_name example.com;

        # 高频访问的日志使用缓冲
        access_log /var/log/nginx/example.com.access.log main 
                   buffer=32k flush=10s;

        location /api {
            # API日志使用较大缓冲
            access_log /var/log/nginx/api.access.log json 
                       buffer=128k flush=30s;
        }
    }
}

6.2 异步日志记录

# 主配置文件
worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 1024;
    use epoll;
}

http {
    # 使用异步I/O
    aio on;
    directio 512;

    # 日志配置
    access_log /var/log/nginx/access.log main buffer=64k flush=5s;

    # 禁用不必要的日志
    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        access_log off;
        expires 1y;
    }
}

7. 安全和审计日志

7.1 安全事件日志

http {
    # 安全日志格式
    log_format security '$remote_addr [$time_local] "$request" '
                       '$status $request_length $body_bytes_sent '
                       '"$http_referer" "$http_user_agent" '
                       '"$http_x_forwarded_for" $request_time';

    # 地理位置映射
    geoip_country /usr/share/GeoIP/GeoIP.dat;
    geoip_city /usr/share/GeoIP/GeoLiteCity.dat;

    # 可疑活动检测
    map $request_method $suspicious_method {
        default 0;
        ~*(TRACE|CONNECT|DEBUG) 1;
    }

    map $http_user_agent $suspicious_ua {
        default 0;
        ~*sqlmap 1;
        ~*nikto 1;
        ~*scanner 1;
    }

    server {
        listen 80;
        server_name example.com;

        # 记录可疑活动
        if ($suspicious_method) {
            access_log /var/log/nginx/security.log security;
        }

        if ($suspicious_ua) {
            access_log /var/log/nginx/security.log security;
        }

        # 404错误特别记录
        location @notfound {
            access_log /var/log/nginx/404.log security;
            return 404;
        }
    }
}

7.2 访问控制日志

http {
    # 访问控制日志格式
    log_format access_control '$remote_addr [$time_local] "$request" '
                             '$status "$rule_matched" "$action_taken"';

    server {
        listen 80;
        server_name example.com;

        # 管理区域访问控制
        location /admin {
            allow 192.168.1.0/24;
            allow 10.0.0.0/8;
            deny all;

            access_log /var/log/nginx/admin_access.log access_control;

            # 记录拒绝的访问
            error_page 403 @access_denied;
        }

        location @access_denied {
            access_log /var/log/nginx/access_denied.log security;
            return 403 "Access Denied";
        }
    }
}

8. 日志集中化管理

8.1 使用rsyslog发送日志

# 配置nginx发送日志到syslog
error_log syslog:server=192.168.1.100:514,facility=local0,tag=nginx,severity=error;
access_log syslog:server=192.168.1.100:514,facility=local0,tag=nginx main;
# /etc/rsyslog.d/nginx.conf
# 接收来自nginx的日志
local0.*    /var/log/nginx/centralized.log

# 转发到远程日志服务器
*.* @@log-server.example.com:514

8.2 使用Fluentd收集日志

# /etc/fluent/conf.d/nginx.conf
<source>
  @type tail
  path /var/log/nginx/access.log
  pos_file /var/log/fluentd/nginx-access.log.pos
  tag nginx.access
  format nginx
</source>

<source>
  @type tail
  path /var/log/nginx/error.log
  pos_file /var/log/fluentd/nginx-error.log.pos
  tag nginx.error
  format /^(?<time>\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[(?<log_level>\w+)\] (?<message>.*)$/
</source>

<match nginx.**>
  @type elasticsearch
  host elasticsearch.example.com
  port 9200
  index_name nginx-logs
</match>

9. 故障排除

9.1 日志问题诊断

# 检查日志目录权限
ls -la /var/log/nginx/

# 检查nginx进程运行用户
ps aux | grep nginx

# 检查磁盘空间
df -h /var/log

# 检查inode使用情况
df -i /var/log

# 测试日志轮转
sudo logrotate -d /etc/logrotate.d/nginx

9.2 常见问题解决

# 日志文件权限问题
sudo chown nginx:nginx /var/log/nginx/*.log
sudo chmod 640 /var/log/nginx/*.log

# 日志目录不存在
sudo mkdir -p /var/log/nginx
sudo chown nginx:nginx /var/log/nginx

# 重新打开日志文件
sudo nginx -s reopen

# 检查SELinux设置
sudo setsebool -P httpd_can_network_connect 1
sudo restorecon -R /var/log/nginx

10. 监控和告警

10.1 日志监控脚本

#!/bin/bash
# nginx-log-monitor.sh

LOG_FILE="/var/log/nginx/access.log"
ERROR_LOG="/var/log/nginx/error.log"
ALERT_EMAIL="admin@example.com"

# 检查4xx错误数量
error_4xx_count=$(tail -1000 $LOG_FILE | grep -c " 4[0-9][0-9] ")
if [ $error_4xx_count -gt 50 ]; then
    echo "High 4xx error rate: $error_4xx_count" | mail -s "Nginx Alert" $ALERT_EMAIL
fi

# 检查5xx错误数量
error_5xx_count=$(tail -1000 $LOG_FILE | grep -c " 5[0-9][0-9] ")
if [ $error_5xx_count -gt 10 ]; then
    echo "High 5xx error rate: $error_5xx_count" | mail -s "Nginx Critical Alert" $ALERT_EMAIL
fi

# 检查响应时间
avg_response_time=$(tail -1000 $LOG_FILE | awk '{print $NF}' | awk '{sum+=$1; count++} END {print sum/count}')
if (( $(echo "$avg_response_time > 2.0" | bc -l) )); then
    echo "High response time: $avg_response_time" | mail -s "Nginx Performance Alert" $ALERT_EMAIL
fi

10.2 使用Prometheus监控

# prometheus.yml配置
scrape_configs:
  - job_name: 'nginx'
    static_configs:
      - targets: ['localhost:9113']
    scrape_interval: 5s
# nginx配置添加状态页面
server {
    listen 8080;
    server_name localhost;

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

小结

通过本文的学习,你应该掌握:

  1. Nginx日志系统的基本概念和类型
  2. 访问日志和错误日志的配置方法
  3. 自定义日志格式和条件日志记录
  4. 日志轮转和归档管理
  5. 日志分析和监控技巧
  6. 性能优化和安全审计
  7. 集中化日志管理方案
  8. 常见问题的诊断和解决

下一篇文章将介绍Nginx的反向代理配置。

powered by Gitbook© 2025 编外计划 | 最后修改: 2025-08-29 15:40:15

results matching ""

    No results matching ""