原標題為「Java 查詢 MongoDB ObjectId」,但實際內容為 Nginx 日誌自動化運維腳本集。本文整理三支核心腳本:日誌切割壓縮、定時清理、錯誤碼/URL/IP 分析,已在生產環境穩定運行。
# 每天 15:01 執行切割腳本,日誌輸出至 cron.log
1 15 * * * /home/dongnan/sh/split.sh >> /home/dongnan/sh/cron.log 2>&1
#!/bin/bash
# 變數區
log_dir=/var/log/nginx/
log_date=$(date +"%Y%m%d")
nginx_pid=/var/run/nginx.pid
keep_days=30
# 清理 30 天前的 .gz 壓縮檔
find "$log_dir" -name "*.log.gz" -type f -mtime +${keep_days} -exec rm -rf {} \;
# 重新命名當前 access.log / error.log 為 日期-檔名.log 並壓縮
for log_name in $(ls "$log_dir" | awk '/\.log$/'); do
if [ -e "${log_dir}${log_date}-${log_name}" ]; then
echo "${log_dir}${log_date}-${log_name} 已存在,跳過"
continue
fi
mv "${log_dir}${log_name}" "${log_dir}${log_date}-${log_name}"
gzip "${log_dir}${log_date}-${log_name}"
done
# 平滑重開 Nginx 讓它寫入新日誌檔
kill -USR1 $(cat $nginx_pid) && sleep 1
#!/bin/bash
NGINX_BIN=$(ps aux | grep nginx | grep root | grep -v grep | awk '{print $14}')
if [ "$NGINX_BIN" = "/usr/local/nginx/sbin/nginx" ]; then
ACCLOG=$(grep 'access_log' /usr/local/nginx/conf/nginx.conf | awk '{print $2}')
ERRLOG=$(grep '^error_log' /usr/local/nginx/conf/nginx.conf | awk '{print $2}' | cut -d';' -f1)
if [ -f "$ACCLOG" ]; then
mv "$ACCLOG" "$ACCLOG.$(date -d '-1 day' +%F)"
mv "$ERRLOG" "$ERRLOG.$(date -d '-1 day' +%F)"
touch "$ACCLOG" "$ERRLOG"
chown nginx:root "$ACCLOG" "$ERRLOG"
[ -f /usr/local/nginx/logs/nginx.pid ] && kill -USR1 $(cat /usr/local/nginx/logs/nginx.pid)
/mnt/logs/checklog.sh "$ACCLOG.$(date -d '-1 day' +%F)" # 呼叫分析腳本
gzip "$ACCLOG.$(date -d '-1 day' +%F)"
gzip "$ERRLOG.$(date -d '-1 day' +%F)"
# 移動 10 天前舊日誌至歸檔目錄
mv "$ACCLOG.$(date -d '-10 day' +%F).*" /mnt/history.nginx.log/
mv "$ERRLOG.$(date -d '-10 day' +%F).*" /mnt/history.nginx.log/
fi
fi
#!/bin/bash
LOG_FILE=$1
echo "####################$(date +%F)" >> /mnt/logs/400.txt
echo "####################$(date +%F)" >> /mnt/logs/URL.txt
echo "####################$(date +%F)" >> /mnt/logs/IP.txt
# 總行數 → IP.txt
wc -l < "$LOG_FILE" >> /mnt/logs/IP.txt
# 狀態碼統計 → CODE.txt
awk -F'"' '{print $3}' "$LOG_FILE" | awk '{print $1}' | sort | uniq -c | sort -rn > /mnt/logs/CODE.txt
# Top 20 IP → IP.txt
awk '{print $1}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -20 >> /mnt/logs/IP.txt
# 400+ 錯誤詳情 → 400.txt
while read count code; do
if [ "$code" -ge 400 ]; then
echo "#####FIND $code###############" >> /mnt/logs/400.txt
grep "\" $code " "$LOG_FILE" | grep -v ' "-" "-" - ' | \
awk '{print $1,$2,$3,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21}' | \
sort | uniq -c | sort -rn | head -5 >> /mnt/logs/400.txt
fi
done < /mnt/logs/CODE.txt
# Top 20 URL(去除查詢字串、正規化 review 下載路徑) → URL.txt
grep -v ' "-" "-" - ' "$LOG_FILE" | \
awk -F'T' '{print $2}' | awk -F'?' '{print $1}' | \
sed 's|\(/review/file/download/\).*|\1|' | \
sort | uniq -c | sort -rn | head -20 >> /mnt/logs/URL.txt
| 指令 | 用途 |
|---|---|
| kill -USR1 `cat nginx.pid` | 平滑重開,讓 Nginx 切換到新日誌檔 |
| awk -F'"' '{print $3}' | 以雙引號分欄,取第 3 欄(含狀態碼) |
| uniq -c | sort -rn | 計數並倒序排序 |
| date -d '-1 day' +%F | 取前一天日期 (YYYY-MM-DD) |
/home/dongnan/sh/ 並 chmod +x。/mnt/history.nginx.log/、分析輸出目錄 /mnt/logs/。nginx.pid 路徑與 nginx.conf 中 log 路徑一致。三支腳本覆蓋「切割→壓縮→分析→歸檔」全生命週期,零依賴、純 Shell 實現,適合任何 Linux+Nginx 環境直接落地。