Blog Details

Linux 作業系統 cutexyz > Blog > 伺服器管理 > 伺服器管理必學 100 招 > 伺服器管理必學 100 招|Part 6:文字處理與日誌排錯神器

伺服器管理必學 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 虛擬主機設定檔中的舊資料庫 IP 10.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)的中小型伺服器上,進行秒級突發效能體檢。