Nginx 預設不支援按日期自動切割日誌,需透過 Shell 腳本配合 crontab 或系統內建 logrotate 實現。本文提供兩種方案並分析優劣。
/usr/local/sbin/cut_nginx_log.sh
#!/bin/bash
# Nginx 日誌切割腳本 - 每日 00:00 執行
LOG_PATH="/var/log/nginx"
DATE=$(date -d "yesterday" +"%Y-%m-%d")
PID_FILE="/var/run/nginx.pid"
# 1. 重命名舊日誌
mv ${LOG_PATH}/access.log ${LOG_PATH}/access_${DATE}.log
mv ${LOG_PATH}/error.log ${LOG_PATH}/error_${DATE}.log
# 2. 發送 USR1 信號讓 Nginx 重新開啟日誌檔 (無需 reload)
kill -USR1 $(cat ${PID_FILE})
# 3. (可選) 壓縮 7 天前的日誌
find ${LOG_PATH} -name "*.log" -mtime +7 -exec gzip {} \;
# 4. (可選) 刪除 30 天前的壓縮日誌
find ${LOG_PATH} -name "*.gz" -mtime +30 -delete
# 每日 00:00 執行
0 0 * * * /usr/local/sbin/cut_nginx_log.sh >> /var/log/nginx_cut.log 2>&1
logrotate 內建壓縮、郵件通知、共享腳本、延遲壓縮等功能,更健壯。
/etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily # 每日輪轉
missingok # 檔案不存在不報錯
rotate 30 # 保留 30 天
compress # 壓縮舊日誌
delaycompress # 延遲一天再壓縮 (配合 sharedscripts)
notifempty # 空檔不輪轉
create 0640 nginx adm # 新建檔案權限/擁有者
sharedscripts # 只執行一次 postrotate
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
dateext # 使用日期作為後綴 (access.log-20240115)
dateformat -%Y-%m-%d
extension .log # 保持 .log 副檔名
}
logrotate -d /etc/logrotate.d/nginx # 偵錯模式 (不實際執行)
logrotate -f /etc/logrotate.d/nginx # 強制執行一次
SIGUSR1 會重新開啟日誌檔案,不中斷服務,優於 reload (會重讀配置、重啟 Worker)。sharedscripts 確保多個日誌檔 (access/error) 只發送一次信號。delaycompress 讓最新的舊日誌保持未壓縮,便於即時分析;次日輪轉時再壓縮。dateext + dateformat 產生 access.log-2024-01-15 格式,利於排序與篩選。
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
# 上傳昨天的日誌到 Elasticsearch/Logstash/S3 等
/usr/local/bin/ship_logs.sh $(date -d "yesterday" +"%Y-%m-%d")
endscript
生產環境強烈建議使用 logrotate,功能完整、穩定可靠、符合 Linux 系統管理規範。Shell 腳本方案僅適合極簡環境或特殊邏輯需求。無論哪種方式,核心關鍵皆為 kill -USR1 平滑切換日誌檔案。