Linux 日誌定時輪詢流程詳解
logrotate介紹
對於Linux系統安全來說,日誌檔案是極其重要的工具。日誌檔案包含了關於系統中發生的事件的有用資訊,在排障過程中或者系統性能分析時經常被用到。當日志文件不斷增長的時候,就需要定時切割,否則,寫日誌的速度和效能也會下降,更不便於我們歸檔,查詢。
所以便有了使用logrotate的時候 ,logrotate是個十分有用的工具,它可以自動對日誌進行截斷(或輪循)、壓縮以及刪除舊的日誌檔案。例如,你可以設定logrotate,讓/var/log/foo日誌檔案每30天輪循,並刪除超過6個月的日誌。配置完後,logrotate的運作完全自動化,不必進行任何進一步的人為干預。
logrotate配置檔案位置
Linux系統預設安裝logrotate工具,它預設的配置檔案在:
12 | /etc/logrotate.conf/etc/logrotate.d/ |
logrotate.conf 才主要的配置檔案,logrotate.d 是一個目錄,該目錄裡的所有檔案都會被主動的讀入/etc/logrotate.conf中執行。
另外,如果 /etc/logrotate.d/ 裡面的檔案中沒有設定一些細節,則會以/etc/logrotate.conf這個檔案的設定來作為預設值。
實際執行時,Logrotate會呼叫配置檔案/etc/logrotate.conf。
可以在/etc/logrotate.d目錄裡放置自定義好的配置檔案,用來覆蓋Logrotate的預設值。
定時輪循機制
Logrotate是基於CRON來執行的,其指令碼是/etc/cron.daily/logrotate,日誌輪轉是系統自動完成的。
logrotate這個任務預設放在cron的每日定時任務cron.daily下面 /etc/cron.daily/logrotate/etc/目錄下面還有cron.weekly/, cron.hourly/, cron.monthly/ 的目錄都是可以放定時任務的
123456789101112131415 | [/etc]$cat/etc/cron.daily/logrotate#!/bin/sh# Clean non existent log file entries from status filecd/var/lib/logrotatetest-estatus||touch statushead-1status>status.cleansed's/"//g'status|whileread logfile datedo[-e"$logfile"]&&echo"\"$logfile\" $date"done>>status.cleanmv status.clean statustest-x/usr/sbin/logrotate||exit0/usr/sbin/logrotate/etc/logrotate.conf |
這裡實際操作輪詢的命令最後一行
/usr/sbin/logrotate /etc/logrotate.conf
定義好了每日執行任務的指令碼cron.daily/logrotate ,再檢視crontab的內容,裡面設定好了對應的cron.xxly
執行時間
123456789 | [/etc]$vim/etc/crontabSHELL=/bin/shPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin# m h dom mon dow user command17****root cd/&&run-parts--report/etc/cron.hourly256***root test-x/usr/sbin/anacron||(cd/&&run-parts--report/etc/cron.daily)476**7root test-x/usr/sbin/anacron||(cd/&&run-parts--report/etc/cron.weekly)5261**root test-x/usr/sbin/anacron||(cd/&&run-parts--report/etc/cron.monthly) |
可以看出來了只要是在
- /etc/cron.daily/ 下面的任務都是每天6:25 執行
- /etc/cron.weekly/ 下面的任務都是每週日 6:47 執行
- /etc/cron.monthly/ 下面的任務都是每月1號 6:52 執行
如果等不及cron自動執行日誌輪轉,想手動強制切割日誌,需要加-f引數;
不過正式執行前最好通過Debug選項來驗證一下(-d引數),這對除錯也很重要
12 | # /usr/sbin/logrotate -f /etc/logrotate.d/nginx // 未到時間或者未到切割條件,強制切割# /usr/sbin/logrotate -d -f /etc/logrotate.d/nginx // 輸出切割debug資訊 |
那麼至此,我們就知道logrotate是如何實現自動切割日誌的
logrotate配置案例
nginx 常用日誌切割配置
12345678910111213141516171819 | /data/log/nginx/*.log /data/log/nginx/*/*.log{# 對匹配上的日誌檔案進行切割weekly# 每週切割missingok# 在日誌輪循期間,任何錯誤將被忽略,例如“檔案無法找到”之類的錯誤。rotate6# 保留 6 個備份compress# 壓縮delaycompress# delaycompress 和 compress 一起使用時,轉儲的日誌檔案到下一次轉儲時才壓縮notifempty# 如果是空檔案的話,不轉儲create0644www-data ymserver# mode owner group 轉儲檔案,使用指定的檔案模式建立新的日誌檔案sharedscripts# 下面詳細說prerotate# 在logrotate轉儲之前需要執行的指令,例如修改檔案的屬性等動作;必須獨立成行if[-d/etc/logrotate.d/httpd-prerotate];then\run-parts/etc/logrotate.d/httpd-prerotate;\fi\endscriptpostrotate# 在logrotate轉儲之後需要執行的指令,例如重新啟動 (kill -HUP) 某個服務!必須獨立成行[-s/run/nginx.pid]&&kill-USR1`cat/run/nginx.pid`endscriptsu root ymserver# 輪訓日誌時切換設定的使用者/使用者組來執行(預設是root),如果設定的user/group 沒有許可權去讓檔案容用 create 選項指定的擁有者 ,會觸發錯誤。} |
如果要配置一個每日0點執行切割任務,怎麼做到?我們的logrotate預設每天執行時間已經寫到了/etc/cron.daily/目錄下面,而這個目錄下面的任務執行時間上面也說了,在/etc/crontab裡面定義了時6:25。我之前就有個這樣的需求,看看下面的配置
1234567891011121314 | /data/log/owan_web/chn_download_stat/chn_app_rec.log{copytruncate# weekly 註釋了 但是會繼承/etc/logrorate.conf的全域性變數,也是weeklymissingokrotate10compressdelaycompresssize=1000M# 大小到達size開始轉存notifemptycreate664www-data ymserversu rootdateext//這個引數很重要!就是切割後的日誌檔案以當前日期為格式結尾,如xxx.log-20131216這樣,如果註釋掉,切割出來是按數字遞增,即前面說的 xxx.log-1這種格式compress//是否通過gzip壓縮轉儲以後的日誌檔案,如xxx.log-20131216.gz ;如果不需要壓縮,註釋掉就行} |
然後去root的crontab配置一個0點執行的任務
12 | wwwadm@host:/etc/logrotate.d$sudo crontab-l-uroot00***/usr/sbin/logrotate/etc/logrotate.d/web_roteate-fv>/tmp/logro.log2>&1 |
因為logrotate的切割週期是weekly,每次切割都是根據上一個切割的時間來進行,如果距離上一次有一週時間,就會切割,但是我們設定了crontab的每天切割,既不會進入/etc/cron.daily/的每日切割,也不會每週切割。這樣就能完美定製自己想要的切割日誌時間
logrotate引數說明
1234567891011121314151617181920212223242526 | compress通過gzip壓縮轉儲以後的日誌nocompress不做gzip壓縮處理create mode owner group輪轉時指定建立新檔案的屬性,如create0777nobody nobodynocreate不建立新的日誌檔案delaycompress和compress一起使用時,轉儲的日誌檔案到下一次轉儲時才壓縮nodelaycompress覆蓋delaycompress選項,轉儲同時壓縮。missingok如果日誌丟失,不報錯繼續滾動下一個日誌ifempty即使日誌檔案為空檔案也做輪轉,這個是logrotate的預設選項。notifempty當日志文件為空時,不進行輪轉mail address把轉儲的日誌檔案傳送到指定的E-mail地址olddir directory轉儲後的日誌檔案放入指定的目錄,必須和當前日誌檔案在同一個檔案系統noolddir轉儲後的日誌檔案和當前日誌檔案放在同一個目錄下sharedscripts執行postrotate指令碼,作用是在所有日誌都輪轉後統一執行一次指令碼。如果沒有配置這個,那麼每個日誌輪轉後都會執行一次指令碼prerotate在logrotate轉儲之前需要執行的指令,例如修改檔案的屬性等動作;必須獨立成行postrotate在logrotate轉儲之後需要執行的指令,例如重新啟動(kill-HUP)某個服務!必須獨立成行daily指定轉儲週期為每天weekly指定轉儲週期為每週monthly指定轉儲週期為每月rotate count指定日誌檔案刪除之前轉儲的次數,0指沒有備份,5指保留5個備份dateext使用當期日期作為命名格式dateformat.%s配合dateext使用,緊跟在下一行出現,定義檔案切割後的檔名,必須配合dateext使用,只支援%Y%m%d%s這四個引數size(或minsize)log-size當日志文件到達指定的大小時才轉儲,log-size能指定bytes(預設)及KB(sizek)或MB(sizem).當日志文件>=log-size的時候就轉儲。以下為合法格式:(其他格式的單位大小寫沒有試過)size=5或size5(>=5個位元組就轉儲)size=100k或size100ksize=100M或size100M |
值得注意的一個配置是:copytruncate
copytruncate
如果沒有這個選項的話,操作方式:是將原log日誌檔案,移動成類似log.1的舊檔案, 然後建立一個新的檔案。 如果設定了,操作方式:拷貝原日誌檔案,並且將其變成大小為0的檔案。
區別是如果程序,比如nginx 使用了一個檔案寫日誌,沒有copytruncate的話,切割日誌時, 把舊日誌log->log.1 ,然後建立新日誌log。這時候nginx 開啟的檔案描述符依然時log.1,由沒有訊號通知nginx 要換日誌描述符,所以它會繼續向log.1寫日誌,這樣就不符合我們的要求了。 因為我們想切割日誌後,nginx 自動會向新的log 檔案寫日誌,而不是舊的log.1檔案
解決方法有兩個:
1.向上面的nginx 切割日誌配置,再postrotate裡面寫個指令碼
123 | postrotate# 在logrotate轉儲之後需要執行的指令,例如重新啟動 (kill -HUP) 某個服務!必須獨立成行[-s/run/nginx.pid]&&kill-USR1`cat/run/nginx.pid`endscript |
這樣就是發訊號給nginx ,讓nginx 關閉舊日誌檔案描述符,重新開啟新的日誌檔案描述,並寫入日誌
2.使用copytruncate
引數,向上面說的,配置了它以後,操作方式是把log 複製一份 成為log.1,然後清空log的內容,使大小為0,那此時log依然時原來的舊log,對程序(nginx)來說,依然開啟的是原來的檔案描述符,可以繼續往裡面寫日誌,而不用傳送訊號給nginx
copytruncate這種方式操作的時候, 拷貝和清空之間有一個時間差,可能會丟失部分日誌資料。
nocopytruncate
備份日誌檔案不過不截斷