Apache 日誌是排查性能瓶頸、安全入侵、業務異常的「黑盒記錄儀」。掌握 LogFormat 定義、CustomLog/ErrorLog 切割輪轉、常見字段語義與高頻分析腳本,能將海量文本轉化為可決策洞察。
| 日誌類型 | 指令 | 用途 | 典型位置 |
|---|---|---|---|
| 訪問日誌 | CustomLog | 記錄所有 HTTP 請求:客戶端 IP、請求行、狀態碼、流量、UA、Referer | /var/log/apache2/access.log 或 /var/log/httpd/access_log |
| 錯誤日誌 | ErrorLog | 記錄服務器錯誤、啟動警告、模組異常、腳本報錯 | /var/log/apache2/error.log 或 /var/log/httpd/error_log |
# Apache 配置片段
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combinedproxy
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
# 虛擬主機獨立日誌 + 每日切割 (rotatelogs)
CustomLog "| /usr/sbin/rotatelogs /var/log/apache2/%Y_%m_%d_vhost_access.log 86400 480" vhost_combined
ErrorLog "| /usr/sbin/rotatelogs /var/log/apache2/%Y_%m_%d_vhost_error.log 86400 480"
218.19.140.242 - - [10/Dec/2010:09:31:17 +0800] "GET /query/trendxml/district/todayreturn/month/2009-12-14/2010-12-09/haizhu_tianhe.xml HTTP/1.1" 200 1933 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 (.NET CLR 3.5.30729)"
│ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ └─ 9. User-Agent: 客戶端瀏覽器/爬蟲標識
│ │ │ │ │ │ │ └─ 8. Referer: 來源頁面 (防盜鏈/來源分析)
│ │ │ │ │ │ └─ 7. 響應體積節: 响应字节数 (不含頭部)
│ │ │ │ │ └─ 6. 狀態碼: 2xx 成功、3xx 重定向、4xx 客戶端錯誤、5xx 服務端錯誤
│ │ │ │ └─ 5. 請求行: "Method URI Protocol"
│ │ │ └─ 4. 時間戳: [Day/Mon/Year:Hour:Min:Sec Zone]
│ │ └─ 3. 認證用戶: HTTP Basic Auth 用戶名 (無則 -)
│ └─ 2. RFC1413 身份: identd 返回 (極少用,通常 -)
└─ 1. 客戶端 IP: 真實 IP 或代理 IP (若有 X-Forwarded-For 需解析)
| 符號 | 含義 | 示例 |
|---|---|---|
%h | 遠程主機名/IP | 218.19.140.242 |
%l | RFC1413 身份 (通常 -) | - |
%u | 認證用戶 | - |
%t | 標準時間 [Day/Mon/Year:Hour:Min:Sec Zone] | [10/Dec/2010:09:31:17 +0800] |
%r | 請求行 "Method URI Protocol" | "GET /api HTTP/1.1" |
%>s | 最終狀態碼 (重定向後) | 200 |
%b | 響應字節數 (CLF 格式,無則 -) | 1933 |
%{Header}i | 請求頭 Header | %{Referer}i, %{User-Agent}i |
%{Header}o | 響應頭 Header | %{Content-Type}o |
%D | 請求處理時間 (微秒) | 125000 |
%T | 請求處理時間 (秒) | 0.125 |
%P | 子進程 PID | 12345 |
[Fri Dec 10 15:03:59 2010] [error] [client 218.19.140.242] File does not exist: /home/htmlfile/tradedata/favicon.ico
│ │ │ │
│ │ │ └─ 4. 具體錯誤描述
│ │ └─ 3. 客戶端 IP
│ └─ 2. 錯誤級別: emerg/alert/crit/error/warn/notice/info/debug (受 LogLevel 控制)
└─ 1. 時間戳 (格式與 access_log 不同)
LogLevel warn 生產推薦;調試時臨時改 debug。
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
rotatelogs (Apache 內建) | 無外部依賴、管道寫入不阻塞主進程 | 無壓縮、無郵件通知、配置較死板 | 中小流量、單機 |
logrotate (系統標準) | 壓縮、郵件、共享腳本、postrotate 執行 reload | 需 reload 釋放文件句柄、極高併發可能丟行 | 生產標準 |
cronolog | 按日期目錄自動建立、高性能 | 需額外安裝 | 大流量、多虛擬主機 |
| Syslog/Journal + rsyslog | 集中化、結構化、可接入 ELK | 配置複雜、需解析 | 雲原生、微服務 |
/etc/logrotate.d/apache2
/var/log/apache2/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 640 root adm
sharedscripts
postrotate
/usr/sbin/apache2ctl graceful > /dev/null
endscript
}
#!/bin/bash
# analyze_apache.sh - 通用 Apache 日誌分析工具箱
LOG_FILE="${1:-/var/log/apache2/access.log}"
DATE_FILTER="${2:-$(date -d 'yesterday' '+%d/%b/%Y')}"
echo "===== 分析日期: $DATE_FILTER ====="
# 1. 當日總 PV / UV
echo "--- PV / UV ---"
grep "$DATE_FILTER" "$LOG_FILE" | wc -l
grep "$DATE_FILTER" "$LOG_FILE" | awk '{print $1}' | sort -u | wc -l
# 2. TOP 20 客戶端 IP
echo "--- TOP 20 IP ---"
grep "$DATE_FILTER" "$LOG_FILE" | awk '{print $1}' | sort | uniq -c | sort -nr | head -20
# 3. TOP 20 URL (含查詢串)
echo "--- TOP 20 URL ---"
grep "$DATE_FILTER" "$LOG_FILE" | awk '{print $7}' | sort | uniq -c | sort -nr | head -20
# 4. 狀態碼分布
echo "--- 狀態碼分布 ---"
grep "$DATE_FILTER" "$LOG_FILE" | awk '{print $9}' | sort | uniq -c | sort -nr
# 5. TOP 10 User-Agent
echo "--- TOP 10 UA ---"
grep "$DATE_FILTER" "$LOG_FILE" | awk -F'"' '{print $6}' | sort | uniq -c | sort -nr | head -10
# 6. 慢請求 TOP 20 (需 %D 微秒字段)
echo "--- 慢請求 TOP 20 (ms) ---"
grep "$DATE_FILTER" "$LOG_FILE" | awk '{print $NF/1000 " " $7}' | sort -nr | head -20
# 7. 疑似攻擊掃描 (404 高頻 IP)
echo "--- 404 攻擊源 TOP 10 ---"
grep "$DATE_FILTER" "$LOG_FILE" | awk '$9==404 {print $1}' | sort | uniq -c | sort -nr | head -10
# 8. 帶寬統計 (GB)
echo "--- 帶寬統計 ---"
awk -v d="$DATE_FILTER" '$4 ~ d {sum+=$10} END {printf "%.2f GB\n", sum/1024/1024/1024}' "$LOG_FILE"
# LogFormat 直接輸出 JSON (Apache 2.4+)
LogFormat "{\"time\":\"%{%Y-%m-%dT%H:%M:%S%z}t\",\"remote_ip\":\"%h\",\"request\":\"%r\",\"status\":%>s,\"bytes\":%b,\"referer\":\"%{Referer}i\",\"ua\":\"%{User-Agent}i\",\"duration_us\":%D}" json_combined
CustomLog "| /usr/bin/tee -a /var/log/apache2/json_access.log | /usr/bin/logger -t apache_json" json_combined
# Filebeat 讀取 json_access.log → Logstash/Ingest Pipeline → Elasticsearch → Kibana 儀表板
格式標準化 → 切割自動化 → 腳本常態化 → 結構化入湖 = 從「看日誌」到「用日誌」的質變。
建立日誌分析 SOP,讓每一次異常都能在 5 分鐘內定位根因。