Linux 日誌架構演進
| 代數 | 組件 | 特點 |
| 第 1 代 | syslogd / klogd | BSD 經典,UDP 514,文本文件,功能極簡 |
| 第 2 代 | syslog-ng / rsyslog | TCP/TLS/RELP、豐富過濾、模塊化、高性能 |
| 第 3 代 | systemd-journald | 二進制日誌、索引查詢、元數據豐富、前向安全封存 |
現代發行版通常 **rsyslog + journald 共存**:journald 收集內核/系統服務日誌 → 轉發給 rsyslog → 寫入文本文件 / 轉發遠程。
rsyslog 配置詳解
配置文件結構
/etc/rsyslog.conf
/etc/rsyslog.d/*.conf # 模塊化片段
核心語法:選擇器 + 動作
# 選擇器: facility.priority
# facility: auth, authpriv, cron, daemon, kern, lpr, mail, news, syslog, user, uucp, local0-7
# priority: debug, info, notice, warning, err, crit, alert, emerg (遞增)
# * 表示所有,.= 精確匹配,.! 排除
# 動作: 文件、用戶、設備、遠程主機、管道、腳本
# 經典範例
*.info;mail.none;authpriv.none;cron.none /var/log/messages
authpriv.* /var/log/secure
mail.* /var/log/maillog
cron.* /var/log/cron
*.emerg :omusrmsg:* # 所有用戶終端
uucp,news.crit /var/log/spooler
local7.* /var/log/boot.log
進階過濾 (RainerScript)
# 表達式過濾
if $programname == 'nginx' and $msg contains 'error' then /var/log/nginx-error.log
& stop
# 正則過濾
if $msg =~ 'failed.*login' then /var/log/failed-login.log
# 動態文件名 (按日期/主機)
template(name="DynFile" type="string" string="/var/log/remote/%HOSTNAME%/%$YEAR%-%$MONTH%-%$DAY%.log")
*.* ?DynFile
遠程轉發 (中心化日誌)
# 客戶端: TCP + TLS (推薦)
*.* @@logserver.example.com:6514
# 或 RELP (可靠)
*.* :omrelp:logserver.example.com:2514
# 服務端: 接收
module(load="imtcp")
input(type="imtcp" port="514" ruleset="remote")
module(load="imrelp")
input(type="imrelp" port="2514" ruleset="remote")
template(name="RemoteFmt" type="string" string="%TIMESTAMP% %HOSTNAME% %syslogtag%%msg%\n")
ruleset(name="remote") {
action(type="omfile" dynaFile="RemoteFmt")
}
systemd-journald 核心操作
journalctl 常用查詢
# 所有日誌
journalctl
# 當前啟動
journalctl -b
journalctl -b -1 # 上次啟動
# 指定服務
journalctl -u nginx
journalctl -u nginx -f # 跟蹤
# 時間範圍
journalctl --since "2024-01-01 00:00:00" --until "2024-01-02"
journalctl --since "1 hour ago"
journalctl --since yesterday
# 優先級
journalctl -p err
journalctl -p 3 # 0=emerg ... 7=debug
# 字段過濾
journalctl _SYSTEMD_UNIT=nginx.service _PID=1234
journalctl _COMM=sshd
# 輸出格式
journalctl -o json-pretty
journalctl -o short-iso
journalctl -o cat # 純消息
持久化配置
# /etc/systemd/journald.conf
[Journal]
Storage=persistent # 持久化到 /var/log/journal
Compress=yes
Seal=yes # 前向安全封存
SplitMode=uid
SyncIntervalSec=5m
RateLimitIntervalSec=30s
RateLimitBurst=10000
SystemMaxUse=2G # 最大佔用
SystemMaxFileSize=200M
RuntimeMaxUse=500M
MaxFileSec=1month
ForwardToSyslog=yes # 轉發給 rsyslog
常見日誌文件速查
| 文件 | 來源 | 內容 |
| /var/log/messages | rsyslog (kern, user 等) | 通用系統日誌 (RHEL 系) |
| /var/log/syslog | rsyslog | 通用系統日誌 (Debian 系) |
| /var/log/secure | rsyslog (authpriv) | 認證/授權日誌 (SSH、sudo、login) |
| /var/log/auth.log | rsyslog (auth) | 認證日誌 (Debian 系) |
| /var/log/maillog | rsyslog (mail) | 郵件系統日誌 |
| /var/log/cron | rsyslog (cron) | 定時任務日誌 |
| /var/log/boot.log | rsyslog (local7) | 啟動過程日誌 |
| /var/log/dmesg | 內核環形緩衝區 | 內核啟動日誌 (dmesg 命令) |
| /var/log/wtmp | login 程序 | 登入/登出二進制記錄 (last 命令) |
| /var/log/btmp | login 程序 | 失敗登入記錄 (lastb 命令) |
| /var/log/httpd/access_log | Apache | 訪問日誌 |
| /var/log/httpd/error_log | Apache | 錯誤日誌 |
| /var/log/nginx/access.log | Nginx | 訪問日誌 |
| /var/log/nginx/error.log | Nginx | 錯誤日誌 |
| /var/log/mysqld.log | MySQL | 錯誤/慢查詢/一般日誌 |
日誌輪轉
logrotate 配置
# /etc/logrotate.d/syslog
/var/log/messages /var/log/secure /var/log/maillog /var/log/cron /var/log/spooler /var/log/boot.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
sharedscripts
postrotate
/bin/kill -HUP $(cat /var/run/syslogd.pid 2>/dev/null) 2>/dev/null || true
/bin/kill -HUP $(cat /var/run/rsyslogd.pid 2>/dev/null) 2>/dev/null || true
endscript
}
# Nginx 範例
/var/log/nginx/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 0640 nginx adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
}
關鍵參數
| 參數 | 含義 |
| daily/weekly/monthly | 輪轉頻率 |
| rotate N | 保留 N 個舊文件 |
| compress | 壓縮舊文件 (gzip) |
| delaycompress | 下次輪轉時再壓縮 (保證最新一個未壓縮) |
| missingok | 文件不存在不報錯 |
| notifempty | 文件為空不輪轉 |
| create mode owner group | 輪轉後建立新文件屬性 |
| sharedscripts | postrotate 腳本只執行一次 |
| copytruncate | 複製後截斷原文件 (用於無法重啟的進程) |
| su user group | 以指定用戶執行輪轉 |
| maxage N | 超過 N 天強制刪除 |
強制執行/除錯
logrotate -f /etc/logrotate.conf # 強制執行
logrotate -d /etc/logrotate.d/nginx # 除錯模式 (不實際操作)
日誌分析實戰
文本工具管道
# SSH 失敗登入 IP 統計
grep "Failed password" /var/log/secure | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -20
# Nginx 訪問統計
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
# 慢請求分析 (Nginx $request_time)
awk '$NF > 1.0 {print}' /var/log/nginx/access.log
# 錯誤趨勢
grep "error" /var/log/nginx/error.log | cut -d' ' -f1-2 | uniq -c
結構化查詢 (journalctl + jq)
journalctl -u nginx -o json | jq -r 'select(.MESSAGE | contains("error")) | "\(.TIMESTAMP) \(.MESSAGE)"'
專用分析工具
- GoAccess:HTML 報表、實時終端界面 `goaccess /var/log/nginx/access.log --log-format=COMBINED -o report.html`
- Graylog/ELK/EFK:集中式日誌平台
- Loki + Grafana:輕量級日誌聚合
- Fail2Ban:基於日誌自動封禁惡意 IP
最佳實踐
- 統一時間源:所有節點 NTP 同步,日誌時間戳一致
- 結構化日誌:應用輸出 JSON,避免正則解析脆弱
- 分級存儲:熱數據 SSD (近 7 天),溫數據 HDD (30 天),冷數據對象存儲 (年)
- 敏感信息脫敏:密碼、Token、PII 不入日誌
- 關鍵業務日誌獨立文件:便於告警與審計
- 遠程轉發加密:TLS/RELP 防竄改竊聽
- 定期演練日誌恢復:驗證備份完整性