伺服器管理必學 100 招|Part 6:文字處理與日誌排錯神器
前言
「線上故障發生時,誰能在最短時間內從數百萬行的日誌中還原真相,誰就能掌握除錯的主動權。」在沒有 GUI 圖形介面的純文字伺服器環境中,文字處理三劍客(Grep、Sed、Awk)與 Systemd 日誌過濾器就是工程師的「聽診器」。本篇精選 10 個核心文字處理與日誌排錯技巧,教你如何高速篩選時間區段、秒級統計攻擊來源、批次修改跨檔配置,並建立穩定的日誌輪替機制。
技巧 051:精準時空追蹤!善用 journalctl 條件式日誌調閱
- 痛點場景:
客戶回報「今天早上 10:15 系統噴錯」,直接下journalctl會從幾個月前的日誌開始傾倒,終端機刷屏數萬行,難以定位關鍵事件。 - 解決方案:
使用journalctl原生支援的時間區間、服務單元與日誌等級過濾:
# 1. 篩選特定時間範圍內的日誌(支援自然語言與標準時間格式)
sudo journalctl --since "2026-10-05 10:00:00" --until "2026-10-05 10:30:00"
# 2. 僅查詢指定服務(myapp)且嚴重等級為 Error 以上的日誌
# 等級:emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6), debug (7)
sudo journalctl -u myapp -p err..emerg
# 3. 僅查看本次開機(Current Boot)以來的輸出,排除舊開機紀錄
sudo journalctl -b
- 專家提醒:
加上-e(跳至檔案末尾)與-f(持續追蹤即時輸出)可快速切換到最新日誌串流,例如journalctl -u nginx -fe。
技巧 052:排查流量刺客!用 awk 一秒統計 Access Log 前十大惡意 IP
- 痛點場景:
伺服器負載異常升高或頻寬被刷爆,需要立刻知道是哪個來源 IP 在發起高頻請求,以便在防火牆封鎖。 - 解決方案:
利用awk提取 Nginx / Apache 存取日誌的首欄(Client IP),結合排序與計數管線:
# 統計存取次數最高的前 10 名 IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -n 10
# 若只想統計 HTTP 狀態碼為 500 或 404 的來源 IP:
# 假設狀態碼位於第 9 欄位
awk '$9 == "500" {print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -n 10
- 專家提醒:
如果日誌檔案已達數 GB,使用LC_ALL=C sort能略過字符集解碼,將排序速度提升 3 到 5 倍。
技巧 053:極速跨檔案搜尋!用 grep 遞迴抓取錯誤棧堆與密鑰
- 痛點場景:
專案拋出未捕捉例外DatabaseConnectionException,但不知道出現在哪一個歷史日誌檔案或原始碼檔案中。 - 解決方案:
善用grep遞迴、忽略大小寫與行號定位功能:
# -r: 遞迴搜尋子目錄
# -n: 標記檔案行號
# -I: 自動忽略二進制檔案(避免終端亂碼)
# -i: 忽略大小寫
grep -rniI "DatabaseConnectionException" /var/log/myapp/
# 搜尋關鍵字並同時印出上下文前後 3 行(關鍵背景資訊)
grep -C 3 "FATAL ERROR" /var/log/syslog
- 專家提醒:
若系統有安裝ripgrep(rg),其搜尋速度比傳統grep快數倍,且預設會智慧忽略.git與二進制檔案。
技巧 054:解密壓縮日誌!直接檢索 .gz 歸檔而無需手動解壓
- 痛點場景:
Logrotate 每天都會將舊日誌壓縮為access.log.2.gz。如果要追查上週的一筆交易,必須手動gunzip解開,既浪費硬碟空間又繁瑣。 - 解決方案:
使用 Z 系列指令(zcat、zgrep、zless),直接在核心記憶體流中解壓並搜尋:
# 搜尋所有壓縮後的舊日誌檔案中包含 "payment/callback" 的紀錄
zgrep "payment/callback" /var/log/nginx/access.log.*.gz
# 在壓縮日誌中執行 awk 管道分析
zcat /var/log/nginx/access.log.2.gz | awk '{print $7}' | sort | uniq -c | sort -rn | head -n 10
- 專家提醒:
zless支援用方向鍵捲動瀏覽大型壓縮檔,按/即可快速搜尋關鍵字,操作邏輯與標準less完全一致。
技巧 055:自動化日誌輪替!配置 logrotate 防止硬碟被撐爆
- 痛點場景:
自建的 Python、Go 或 Node.js 程式日誌越寫越大,幾個月後單一檔案達數十 GB,伺服器無預警因硬碟滿載而崩潰。 - 解決方案:
在/etc/logrotate.d/myapp建立專屬輪替規則:
/var/log/myapp/*.log {
daily # 每天輪替一次
missingok # 若檔案不存在不報錯
rotate 14 # 保留最近 14 天的歷史日誌
compress # 輪替後使用 gzip 壓縮
delaycompress # 延遲一天再壓,避免當前寫入衝突
notifempty # 空檔案不進行輪替
create 0640 deployer deployer # 輪替後新建空日誌檔的權限與擁有者
sharedscripts
postrotate
# 輪替後通知應用程式重新打開檔案描述符(或發送 HUP 訊號)
systemctl reload myapp > /dev/null 2>&1 || true
endscript
}
- 手動觸發測試(Dry Run 驗證語法):
sudo logrotate -d /etc/logrotate.d/myapp
- 專家提醒:
若應用程式不支援reload重新綁定日誌描述符,可在規則中加入copytruncate,先拷貝舊日誌再就地截斷當前檔案。
技巧 056:批次跨檔安全替換!利用 sed 秒改多個設定檔
- 痛點場景:
需要將 20 個 Nginx 虛擬主機設定檔中的舊資料庫 IP10.0.1.5全部更新為新節點10.0.1.80,手動用 vim 編輯極易改漏。 - 解決方案:
使用sed -i直接在檔案內進行串流正規替換,並強制建立備份:
# -i.bak 會在原地修改前,先將原檔案備份為 .bak
sed -i.bak 's/10\.0\.1\.5/10\.0\.1\.80/g' /etc/nginx/sites-available/*.conf
# 若只想精準修改包含特定關鍵字的那一行:
# 僅在包含 "DB_HOST" 的行,將舊字串替換為新字串
sed -i '/DB_HOST/s/localhost/127.0.0.1/' /var/www/*/.env
- 專家提醒:
若替換內容包含 URL 或目錄路徑(斜線/),可將分隔符號改為井號#或豎線|,避免寫出眼花撩亂的反斜線轉義,例如sed -i 's#/var/www/v1#/var/www/v2#g' config.txt。
技巧 057:即時動態追蹤與高亮!tail -f 搭配 multitail
- 痛點場景:
前後端服務分開寫入不同的日誌檔(如api.log與error.log),切換終端機視窗容易錯過錯誤發生的先後順序。 - 解決方案:
# 原生 tail 併發追蹤:
# 同時追蹤多個日誌,有新日誌時會標註檔案標題
tail -f /var/log/nginx/access.log /var/log/nginx/error.log
# 終端多分割視窗神器 multitail:
sudo apt install multitail -y
# 左右切割視窗同時捲動兩個日誌檔,並自動高亮關鍵字
multitail -s 2 /var/log/nginx/access.log /var/log/myapp/error.log
- 專家提醒:
如果日誌正在被 Logrotate 輪替,使用tail -F(大寫 F)會在檔案被刪除重建後自動重新追蹤,防止監控中斷。
技巧 058:終端互動式排查神器!善用 less 快捷導航
- 痛點場景:
使用vim打開幾百 MB 的 Log 檔常導致伺服器記憶體吃滿甚至當機;而cat一下子滾到最底,無法向上檢閱。 - 解決方案:
less不會在啟動時讀取整個檔案,開啟極速且記憶體佔用極低:
less /var/log/syslog
less高頻高效操作鍵:- 按
Shift + G:直接跳至檔案最底端(查看最新 Log)。 - 按
g:回到檔案最開頭。 - 按
/輸入字串:向下搜尋(按n跳下一筆,N跳上一筆)。 - 按
?輸入字串:向上逆向搜尋。 - 按
Shift + F:進入即時監控模式(等同於tail -f);按Ctrl + C可退回靜態瀏覽狀態。
- 按
- 專家提醒:
加上-S參數(less -S file.log)可以強制長行不折行(Line Truncate),改用左右方向鍵捲動,這在檢視排版規律的表格或存取日誌時極為清晰。
技巧 059:去重與差異對比!善用 sort、uniq 與 diff
- 痛點場景:
更新了環境配置但服務啟動失敗,需要快速比對「當前設定檔」與「備份設定檔」究竟改動了哪一行。 - 解決方案:
# 乾淨對比檔案差異(排除空行與註解):
diff -u -B -w nginx.conf.bak nginx.conf
# 提取不重複資料並計算頻率:
# 提取所有登入失敗的帳號名冊並去重
grep "Failed password for" /var/log/auth.log | awk '{print $(NF-5)}' | sort -u
- 專家提醒:
使用uniq前必須先經由sort排序,因為uniq只能過濾相鄰的重複行。
技巧 060:快速統計 API 響應時間!awk 算術平均與百分位數
- 痛點場景:
使用者抱怨網站偶爾卡頓,想知道某一支 API 在過去一小時內的平均回應時間(Response Time)與最慢請求。 - 解決方案:
在 Nginx 日誌格式中加入$request_time(假設為日誌的最後一欄),並用awk快速計算:
# 統計 /api/checkout 請求的總次數、平均響應秒數與最大響應時間
awk '$7 ~ /^\/api\/checkout/ { count++; sum+=$NF; if($NF>max) max=$NF } END { printf "請求總數: %d | 平均耗時: %.3f 秒 | 最長耗時: %.3f 秒\n", count, sum/count, max }' /var/log/nginx/access.log
- 專家提醒:
這類快速命令列分析適合在尚未部署 APM(如 Datadog、Elasticsearch)的中小型伺服器上,進行秒級突發效能體檢。