網站出錯時開著tail -f看日誌,畫面卻突然沒有新行;稍後打開app.log,又發現紀錄其實一直在增加。先別急著重啟網站。日誌可能已經輪替,眼前的tail還跟著舊檔,而程式已經寫進另一個同名新檔。GNU tail的-f與-F追蹤方式不同,選對方式才能繼續看新紀錄。
同一個檔名,不一定是同一個檔案
許多網站會把app.log改名成app.log.1,再建立新的app.log。路徑看起來沒變,但原來的檔案與新檔已經分開。GNU tail預設的-f以檔案描述符追蹤,檔案被改名後,仍會讀它原本開啟的那個檔案。這對需要繼續看原檔的情境有用,卻不是每位站長追最新網站日誌時想要的結果。
先核對tail所在的機器、容器與路徑。正式站可能把日誌寫在容器內或輸出到標準輸出,你在宿主機看到的同名檔案未必是網站目前使用的來源。不要只因為名稱是error.log,就認定它一定包含這個網站的新錯誤。讀取沒有權限或日誌根本沒有新增,與輪替造成追蹤舊檔是不同問題。
tail --version
ls -li /path/to/app.log /path/to/app.log.1
追蹤新同名檔案,用GNU tail的-F
若你想追蹤的是這個路徑後來出現的新檔,可以用大寫-F。GNU tail把它定義成–follow=name與–retry的組合:依名稱追蹤,檔案暫時不存在或無法開啟時仍持續重試。這個選項適合改名舊檔、再建立新同名檔的輪替方式。
大小寫不能省略。-f與-F並不是同一個選項的兩種寫法;複製指令後要確認大寫F。下方-n 50表示開始時先顯示最後五十行,再繼續追蹤;你可以依排查需要調整行數。結束前台追蹤按Ctrl+C即可,不需要停止網站服務。
這裡討論的是GNU coreutils的tail,範例環境是Ubuntu 24.04與GNU coreutils 9.4。其他系統、BusyBox或精簡容器內的tail,支援的選項及行為可能不同。先用版本資訊與該環境的手冊核對,不要看到Linux就假設所有tail版本完全一樣。
tail -n 50 -F /path/to/app.log
用兩個終端,觀察輪替前後
想看清楚差異,可以在自己新建的測試目錄用普通文字檔重現,不需要動正式日誌。先建立app.log;在兩個終端進入同一個測試目錄,分別啟動-f與-F。為了只看啟動後新增的內容,兩邊都使用-n 0。最後在第三個終端依序追加文字、改名舊檔、建立新檔。
各步之間稍等一下,讓追蹤程序有時間讀到資料。輪替前的BEFORE_ROTATION應該兩邊都能看到。改名後,新的app.log寫入AFTER_ROTATION;-F會重新開啟這個路徑,繼續讀新檔。這個示例把輪替縮成兩條檔案操作指令,用來解釋檔案身份,不是要你在正式站手動改名正在使用的日誌。
mkdir tail-demo
cd tail-demo
printf "BOOT\n" > app.log
# 終端一,在相同目錄
tail -n 0 -f app.log
# 終端二,在相同目錄
tail -n 0 -F app.log
# 終端三,按步驟執行並稍等
printf "BEFORE_ROTATION\n" >> app.log
mv app.log app.log.1
printf "AFTER_ROTATION\n" > app.log
舊檔仍在新增,是另一個重要訊號
再往app.log.1寫一行LATE_OLD_FILE、往app.log寫一行LATE_NEW_FILE,你會更容易分清兩個追蹤目標。範例中-f看到舊檔後續新增的一行;-F則看到新檔後續新增的一行。它們都在工作,只是讀的檔案不同。
真實網站若輪替後仍把新訊息寫入舊檔,問題可能在產生日誌的程式還沒有重新開啟檔案。切換成-F不會替程式做這件事。需要核對應用程式或Web伺服器原有的輪替安排,由維護者按它的文件處理重新開啟日誌;不要為了看tail有沒有更新,臨時重啟所有服務。
可以先比較新舊檔案的修改時間、大小與近期內容,再確認產生日誌的程序是哪一個。若舊檔持續長大而新檔不動,就不應把「-F畫面沒新增」當成網站沒有事件。日誌來源與追蹤工具要分開查。
printf "LATE_OLD_FILE\n" >> app.log.1
printf "LATE_NEW_FILE\n" >> app.log
ls -li app.log app.log.1
copytruncate與改名重建要分開看
有些輪替方式不是改名重建,而是複製舊內容後截短原檔,也就是常見的copytruncate。在這種情況,原路徑與檔案身份可能仍維持,不能拿改名重建的範例直接解釋所有輪替行為。GNU tail會對檔案縮短作出處理,但這不表示輪替過程沒有資料遺失風險。
logrotate的手冊說明,複製與截短之間存在短暫時間差,這段期間寫入的資料可能遺失。換tail選項不會補回那段資料。如果你的排查涉及稽核、交易或需要完整保留的日誌,應由維護者核對輪替方案、應用程式重開檔的能力與集中日誌安排,不能只靠一個追蹤畫面確認完整性。
這篇先處理最常見的「尾端視窗停住,但新檔已有資料」問題,不修改logrotate設定。現有正式輪替方式要從實際設定與程序行為確認,避免把示例當成通用配置。
等不到新行,按來源一步一步查
-F仍沒有新行時,先確認程式真的在產生新紀錄,以及目前寫入的路徑是否正確。接著看新檔能否讀取、是否因檔案權限變更而無法開啟;GNU tail的診斷訊息可以提供線索。它持續重試不代表權限問題已經自行解決。
重新發送一個你有權操作的測試請求,再對照時間與對應日誌。不要在正式環境製造大量錯誤或隨意加入敏感內容,只為了讓畫面動起來。確認來源後才決定是否需要調整監看方式。若日誌只存在於服務的標準輸出,應改用該服務或容器原有的日誌讀取入口。
當畫面恢復更新,也要核對新檔是否持續收到後續紀錄。看到一次重新開啟提示,只代表tail偵測到路徑變更;它不能證明網站所有錯誤都已修復,更不能證明輪替過程一行都沒漏。
常見問題
用-F會自動修好日誌輪替嗎?不會。它改善的是依名稱追蹤與重新開啟檔案的方式;應用程式如何寫入、輪替與保存日誌,仍要依原本的維護流程處理。
需要加sudo嗎?先依正常帳號權限與日誌擁有者核對,不能只看到Permission denied就全面提升權限。若需要維護者提供讀取權限,應說清楚目標檔案與用途。
可以把tail當長期監控嗎?它適合短時間查看文字輸出。告警、持久保存、跨機搜尋與輪替完整性仍需要相應的系統;不要把目前終端能看見新行,當成長期監控已建好。
參考資料
GNU通用選項:版本資訊
GNU mv:檔案改名與移動
GNU coreutils:輸出檔案尾段的功能索引
logrotate手冊:copytruncate與輪替設定

評論0