Linux日誌切割神器logrotate原理介紹和配置詳解
前言
在Linux環境中能夠幫助我們分析問題蛛絲馬跡的有效辦法之一便是日誌,常見的如作業系統syslog日誌/var/log/messages
,應用程式Nginx日誌/var/log/nginx/*.log
。但如果伺服器數量較多,日誌檔案大小增長較快,不斷消耗磁碟空間就會觸發告警,如果需要人為定期按照各種維度去手動清理日誌就顯得十分棘手。為了節省空間和方便整理,可以將日誌檔案按時間或大小分成多份,刪除時間久遠的日誌檔案,這就是通常說的日誌滾動(log rotation)。logrotate(GitHub地址) 誕生於 1996/11/19 是一個Linux系統日誌的管理工具,本文會詳細介紹Linux日誌切割神器logroate的原理和配置
logrotate簡介
logrotate ‐ rotates, compresses, and mails system logs
logrotate is designed to ease administration of systems that generate large numbers of log files. It allows automatic rotation, compression, removal, and mailing of log files. Each log file may be handled daily, weekly, monthly, or when it grows too large.
Normally, logrotate is run as a daily cron job. It will not modify a log more than once in one day unless the criterion for that log is based on the log's size and logrotate is being run more than once each day, or unless the -f or --force option is used.
Any number of config files may be given on the command line. Later config files may override the options given in earlier files, so the order in which the logrotate config files are listed is important. Normally, a single config file which includes any other config files which are needed should be used. See below for more information on how to
use the include directive to accomplish this. If a directory is given on the command line, every file in that directory is used as a config file.
If no command line arguments are given, logrotate will print version and copyright information, along with a short usage summary. If any errors occur while rotating logs, logrotate will exit with non-zero status.
logrotate 是一個 linux 系統日誌的管理工具。可以對單個日誌檔案或者某個目錄下的檔案按時間 / 大小進行切割,壓縮操作;指定日誌儲存數量;還可以在切割之後執行自定義命令。
logrotate 是基於 crontab 執行的,所以這個時間點是由 crontab 控制的,具體可以查詢 crontab 的配置檔案 /etc/anacrontab。 系統會按照計劃的頻率執行 logrotate,通常是每天。在大多數的 Linux 發行版本上,計劃每天執行的指令碼位於 /etc/cron.daily/logrotate。
主流 Linux 發行版上都預設安裝有 logrotate 包,如果你的 linux 系統中找不到 logrotate, 可以使用 apt-get 或 yum 命令來安裝。
logrotate執行機制
logrotate 在很多 Linux 發行版上都是預設安裝的。系統會定時執行 logrotate,一般是每天一次。系統是這麼實現按天執行的。crontab 會每天定時執行 /etc/cron.daily 目錄下的指令碼,而這個目錄下有個檔案叫 logrotate。在 centos 上指令碼內容是這樣的:
系統自帶 cron task:/etc/cron.daily/logrotate
,每天執行一次
[root@gop-sg-192-168-56-103 logrotate.d]# cat /etc/cron.daily/logrotate #!/bin/sh /usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf EXITVALUE=$? if [ $EXITVALUE != 0 ]; then /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]" fi exit 0
可以看到這個指令碼主要做的事就是以 /etc/logrotate.conf
為配置檔案執行了 logrotate。就是這樣實現了每天執行一次 logrotate。
因為我的系統執行 /etc/cron.daily
目錄下的指令碼不是我想滾動日誌的時間,所以我把 /etc/cron.daily/logrotate
拷了出來,改了一下 logrotate 配置檔案的路徑,然後在 crontab 里加上一條指定時間執行這個指令碼的記錄,自定義週期滾動日誌就大功告成了。這種自定義的方式有兩點要注意:
- 配置檔案裡一定要配置
rotate 檔案數目
這個引數。如果不配置預設是 0 個,也就是隻允許存在一份日誌,剛切分出來的日誌會馬上被刪除。多麼痛的領悟,說多了都是淚。 - 執行 logrotate 命令最好加
-f
引數,不然有時候配置檔案修改的內容不生效。
很多程式的會用到 logrotate 滾動日誌,比如 nginx。它們安裝後,會在 /etc/logrotate.d
這個目錄下增加自己的 logrotate 的配置檔案。logrotate 什麼時候執行 /etc/logrotate.d
下的配置呢?看到 /etc/logrotate.conf
裡這行,一切就不言而喻了。
include /etc/logrotate.d
logrotate原理
logrotate 是怎麼做到滾動日誌時不影響程式正常的日誌輸出呢?logrotate 提供了兩種解決方案。
- create
- copytruncate
Linux 檔案操作機制
介紹一下相關的 Linux 下的檔案操作機制。
Linux 檔案系統裡檔案和檔名的關係如下圖。
[圖片上傳失敗...(image-bf501c-1573030378572)]
目錄也是檔案,檔案裡存著檔名和對應的 inode 編號。通過這個 inode 編號可以查到檔案的元資料和檔案內容。檔案的元資料有引用計數、操作許可權、擁有者 ID、建立時間、最後修改時間等等。檔案件名並不在元資料裡而是在目錄檔案中。因此檔案改名、移動,都不會修改檔案,而是修改目錄檔案。
借《UNIX 環境高階程式設計》裡的圖說一下程序開啟檔案的機制。
程序每新開啟一個檔案,系統會分配一個新的檔案描述符給這個檔案。檔案描述符對應著一個檔案表。表裡面存著檔案的狀態資訊(O_APPEND
/O_CREAT
/O_DIRECT
...)、當前檔案位置和檔案的 inode 資訊。系統會為每個程序建立獨立的檔案描述符和檔案表,不同程序是不會共用同一個檔案表。正因為如此,不同程序可以同時用不同的狀態操作同一個檔案的不同位置。檔案表中存的是 inode 資訊而不是檔案路徑,所以檔案路徑發生改變不會影響檔案操作。
create
這也就是預設的方案,可以通過 create 命令配置檔案的許可權和屬組設定;這個方案的思路是重新命名原日誌檔案,建立新的日誌檔案。詳細步驟如下:
- 重新命名正在輸出日誌檔案,因為重新命名只修改目錄以及檔案的名稱,而程序操作檔案使用的是 inode,所以並不影響原程式繼續輸出日誌。
- 建立新的日誌檔案,檔名和原日誌檔案一樣,注意,此時只是檔名稱一樣,而 inode 編號不同,原程式輸出的日誌還是往原日誌檔案輸出。
- 最後通過某些方式通知程式,重新開啟日誌檔案;由於重新開啟日誌檔案會用到檔案路徑而非 inode 編號,所以開啟的是新的日誌檔案。
如上也就是 logrotate 的預設操作方式,也就是 mv+create 執行完之後,通知應用重新在新檔案寫入即可。mv+create 成本都比較低,幾乎是原子操作,如果應用支援重新開啟日誌檔案,如 syslog, nginx, mysql 等,那麼這是最好的方式。
不過,有些程式並不支援這種方式,壓根沒有提供重新開啟日誌的介面;而如果重啟應用程式,必然會降低可用性,為此引入瞭如下方式。
copytruncate
該方案是把正在輸出的日誌拷 (copy) 一份出來,再清空 (trucate) 原來的日誌;詳細步驟如下:
- 將當前正在輸出的日誌檔案複製為目標檔案,此時程式仍然將日誌輸出到原來檔案中,此時,原檔名也沒有變。
- 清空日誌檔案,原程式仍然還是輸出到預案日誌檔案中,因為清空檔案只把檔案的內容刪除了,而 inode 並沒改變,後續日誌的輸出仍然寫入該檔案中。
如上所述,對於 copytruncate 也就是先複製一份檔案,然後清空原有檔案。
通常來說,清空操作比較快,但是如果日誌檔案太大,那麼複製就會比較耗時,從而可能導致部分日誌丟失。不過這種方式不需要應用程式的支援即可。
配置logrotate
執行檔案: /usr/sbin/logrotate
主配置檔案: /etc/logrotate.conf
自定義配置檔案: /etc/logrotate.d/*.conf
修改配置檔案後,並不需要重啟服務。
由於 logrotate 實際上只是一個可執行檔案,不是以 daemon 執行。
/etc/logrotate.conf
- 頂層主配置檔案,通過 include 指令,會引入 /etc/logrotate.d
下的配置檔案
[root@gop-sg-192-168-56-103 wangao]# cat /etc/logrotate.conf # see "man logrotate" for details # rotate log files weekly weekly # keep 4 weeks worth of backlogs rotate 4 # create new (empty) log files after rotating old ones create # use date as a suffix of the rotated file dateext # uncomment this if you want your log files compressed #compress # RPM packages drop log rotation information into this directory include /etc/logrotate.d # no packages own wtmp and btmp -- we'll rotate them here /var/log/wtmp { monthly create 0664 root utmp minsize 1M rotate 1 } /var/log/btmp { missingok monthly create 0600 root utmp rotate 1 } # system-specific logs may be also be configured here.
/etc/logrotate.d/
通常一些第三方軟體包,會把自己私有的配置檔案,也放到這個目錄下。 如 yum,zabbix-agent,syslog,nginx 等。
[root@gop-sg-192-168-56-103 logrotate.d]# cat yum /var/log/yum.log { missingok notifempty size 30k yearly create 0600 root root }
執行logrotate
具體 logrotate 命令格式如下:
logrotate [OPTION...] <configfile> -d, --debug :debug 模式,測試配置檔案是否有錯誤。 -f, --force :強制轉儲檔案。 -m, --mail=command :壓縮日誌後,傳送日誌到指定郵箱。 -s, --state=statefile :使用指定的狀態檔案。 -v, --verbose :顯示轉儲過程。
crontab 定時
通常慣用的做法是配合 crontab 來定時呼叫。
crontab -e */30 * * * * /usr/sbin/logrotate /etc/logrotate.d/rsyslog > /dev/null 2>&1 &
手動執行
debug 模式:指定[-d|--debug]
logrotate -d <configfile>
並不會真正進行 rotate 或者 compress 操作,但是會打印出整個執行的流程,和呼叫的指令碼等詳細資訊。
verbose 模式: 指定[-v|--verbose]
logrotate -v <configfile>
會真正執行操作,打印出詳細資訊(debug 模式,預設是開啟 verbose)
logrotate引數
詳細介紹請自行 man logrotate
, 或者線上 man page。
主要介紹下完成常用需求會用到的一些引數。
一個典型的配置檔案如下:
[root@localhost ~]# vim /etc/logrotate.d/log_file /var/log/log_file { monthly rotate 5 compress delaycompress missingok notifempty create 644 root root postrotate /usr/bin/killall -HUP rsyslogd endscript }
- monthly: 日誌檔案將按月輪循。其它可用值為
daily
,weekly
或者yearly
。 - rotate 5: 一次將儲存 5 個歸檔日誌。對於第六個歸檔,時間最久的歸檔將被刪除。
- compress: 在輪循任務完成後,已輪循的歸檔將使用 gzip 進行壓縮。
- delaycompress: 總是與 compress 選項一起用,delaycompress 選項指示 logrotate 不要將最近的歸檔壓縮,壓縮 將在下一次輪循週期進行。這在你或任何軟體仍然需要讀取最新歸檔時很有用。
- missingok: 在日誌輪循期間,任何錯誤將被忽略,例如 “檔案無法找到” 之類的錯誤。
- notifempty: 如果日誌檔案為空,輪循不會進行。
- create 644 root root: 以指定的許可權建立全新的日誌檔案,同時 logrotate 也會重新命名原始日誌檔案。
- postrotate/endscript: 在所有其它指令完成後,postrotate 和 endscript 裡面指定的命令將被執行。在這種情況下,rsyslogd 程序將立即再次讀取其配置並繼續執行。
上面的模板是通用的,而配置引數則根據你的需求進行調整,不是所有的引數都是必要的。
/var/log/log_file { size=50M rotate 5 dateext create 644 root root postrotate /usr/bin/killall -HUP rsyslogd endscript }
在上面的配置檔案中,我們只想要輪詢一個日誌檔案,size=50M 指定日誌檔案大小可以增長到 50MB,dateext 指
示讓舊日誌檔案以建立日期命名。
常見配置引數
daily :指定轉儲週期為每天
weekly :指定轉儲週期為每週
monthly :指定轉儲週期為每月
rotate count :指定日誌檔案刪除之前轉儲的次數,0 指沒有備份,5 指保留 5 個備份
tabooext [+] list:讓 logrotate 不轉儲指定副檔名的檔案,預設的副檔名是:.rpm-orig, .rpmsave, v, 和~
missingok:在日誌輪循期間,任何錯誤將被忽略,例如 “檔案無法找到” 之類的錯誤。
size size:當日志文件到達指定的大小時才轉儲,bytes (預設) 及 KB (sizek) 或 MB (sizem)
compress: 通過 gzip 壓縮轉儲以後的日誌
nocompress: 不壓縮
copytruncate:用於還在開啟中的日誌檔案,把當前日誌備份並截斷
nocopytruncate: 備份日誌檔案但是不截斷
create mode owner group : 轉儲檔案,使用指定的檔案模式建立新的日誌檔案
nocreate: 不建立新的日誌檔案
delaycompress: 和 compress 一起使用時,轉儲的日誌檔案到下一次轉儲時才壓縮
nodelaycompress: 覆蓋 delaycompress 選項,轉儲同時壓縮。
errors address : 專儲時的錯誤資訊傳送到指定的 Email 地址
ifempty :即使是空檔案也轉儲,這個是 logrotate 的預設選項。
notifempty :如果是空檔案的話,不轉儲
mail address : 把轉儲的日誌檔案傳送到指定的 E-mail 地址
nomail : 轉儲時不傳送日誌檔案
olddir directory:儲後的日誌檔案放入指定的目錄,必須和當前日誌檔案在同一個檔案系統
noolddir: 轉儲後的日誌檔案和當前日誌檔案放在同一個目錄下
prerotate/endscript: 在轉儲以前需要執行的命令可以放入這個對,這兩個關鍵字必須單獨成行
更多資訊請參考man logrotate幫助文件
手動執行logrotate演練
logrotate 可以在任何時候從命令列手動呼叫。
呼叫 /etc/lograte.d/ 下配置的所有日誌:
[root@localhost ~]# logrotate /etc/logrotate.conf
要為某個特定的配置呼叫 logrotate:
[root@localhost ~]# logrotate /etc/logrotate.d/log_file
排障過程中的最佳選擇是使用-d
選項以預演方式執行 logrotate。要進行驗證,不用實際輪循任何日誌檔案,
可以模擬演練日誌輪循並顯示其輸出。
[root@localhost ~]# logrotate -d /etc/logrotate.d/log_file reading config file /etc/logrotate.d/log_file reading config info for /var/log/log_file Handling 1 logs rotating pattern: /var/log/log_file monthly (5 rotations) empty log files are not rotated, old logs are removed considering log /var/log/log_file log does not need rotating not running postrotate script, since no logs were rotated
正如我們從上面的輸出結果可以看到的,logrotate 判斷該輪循是不必要的。如果檔案的時間小於一天,這就會發生了。
強制輪循即使輪循條件沒有滿足,我們也可以通過使用-f
選項來強制 logrotate 輪循日誌檔案,-v
引數提供了詳細的輸出。
[root@localhost ~]# logrotate -vf /etc/logrotate.d/log_file reading config file /etc/logrotate.d/log_file reading config info for /var/log/log_file Handling 1 logs rotating pattern: /var/log/log_file forced from command line (5 rotations) empty log files are not rotated, old logs are removed considering log /var/log/log_file log needs rotating rotating log /var/log/log_file, log->rotateCount is 5 dateext suffix '-20180503' glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' previous log /var/log/log_file.1 does not exist renaming /var/log/log_file.5.gz to /var/log/log_file.6.gz (rotatecount 5, logstart 1, i 5), old log /var/log/log_file.5.gz does not exist renaming /var/log/log_file.4.gz to /var/log/log_file.5.gz (rotatecount 5, logstart 1, i 4), old log /var/log/log_file.4.gz does not exist renaming /var/log/log_file.3.gz to /var/log/log_file.4.gz (rotatecount 5, logstart 1, i 3), old log /var/log/log_file.3.gz does not exist renaming /var/log/log_file.2.gz to /var/log/log_file.3.gz (rotatecount 5, logstart 1, i 2), old log /var/log/log_file.2.gz does not exist renaming /var/log/log_file.1.gz to /var/log/log_file.2.gz (rotatecount 5, logstart 1, i 1), old log /var/log/log_file.1.gz does not exist renaming /var/log/log_file.0.gz to /var/log/log_file.1.gz (rotatecount 5, logstart 1, i 0), old log /var/log/log_file.0.gz does not exist log /var/log/log_file.6.gz doesn't exist -- won't try to dispose of it fscreate context set to unconfined_u:object_r:var_log_t:s0 renaming /var/log/log_file to /var/log/log_file.1 creating new /var/log/log_file mode = 0644 uid = 0 gid = 0 running postrotate script set default create context
logrotate配置檔案例項
syslog
[root@gop-sg-192-168-56-103 logrotate.d]# cat syslog /var/log/cron /var/log/maillog /var/log/messages /var/log/secure /var/log/spooler { missingok sharedscripts postrotate /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true endscript }
zabbix-agent
[root@gop-sg-192-168-56-103 logrotate.d]# cat zabbix-agent /var/log/zabbix/zabbix_agentd.log { weekly rotate 12 compress delaycompress missingok notifempty create 0664 zabbix zabbix }
nginx
[root@gop-sg-192-168-56-103 logrotate.d]# cat nginx /var/log/nginx/*.log /var/log/nginx/*/*.log{ daily missingok rotate 14 compress delaycompress notifempty create 640 root adm sharedscripts postrotate [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid` endscript }
influxdb
[root@gop-sg-192-168-56-103 logrotate.d]# cat influxdb /var/log/influxdb/influxd.log { daily rotate 7 missingok dateext copytruncate compress }
關於 USR1 訊號解釋
USR1 亦通常被用來告知應用程式過載配置檔案;例如,向 Apache HTTP 伺服器傳送一個 USR1 訊號將導致以下步驟的發生:停止接受新的連線,等待當前連線停止,重新載入配置檔案,重新開啟日誌檔案,重啟伺服器,從而實現相對平滑的不關機的更改。
對於 USR1 和 2 都可以使用者自定義的,在 POSIX 相容的平臺上,SIGUSR1 和 SIGUSR2 是傳送給一個程序的訊號,它表示了使用者定義的情況。它們的符號常量在標頭檔案 signal.h 中定義。在不同的平臺上,訊號的編號可能發生變化,因此需要使用符號名稱。
kill -HUP pid killall -HUP pName
其中 pid 是程序標識,pName 是程序的名稱。
如果想要更改配置而不需停止並重新啟動服務,可以使用上面兩個命令。在對配置檔案作必要的更改後,發出該命令以動態更新服務配置。根據約定,當你傳送一個掛起訊號 (訊號 1 或 HUP) 時,大多數伺服器程序 (所有常用的程序) 都會進行復位操作並重新載入它們的配置檔案。
logrotate日誌切割輪詢
由於 logrotate 是基於 cron 執行的,所以這個日誌輪轉的時間是由 cron 控制的,具體可以查詢 cron 的配置檔案 /etc/anacrontab,過往的老版本的檔案為(/etc/crontab)
檢視輪轉檔案:/etc/anacrontab
[root@gop-sg-192-168-56-103 logrotate.d]# cat /etc/anacrontab # /etc/anacrontab: configuration file for anacron # See anacron(8) and anacrontab(5) for details. SHELL=/bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root # the maximal random delay added to the base delay of the jobs RANDOM_DELAY=45 # the jobs will be started during the following hours only START_HOURS_RANGE=3-22 #period in days delay in minutes job-identifier command 1 5 cron.daily nice run-parts /etc/cron.daily 7 25 cron.weekly nice run-parts /etc/cron.weekly @monthly 45 cron.monthly nice run-parts /etc/cron.monthly
使用 anacrontab 輪轉的配置檔案,日誌切割的生效時間是在凌晨 3 點到 22 點之間,而且隨機延遲時間是 45 分鐘,但是這樣配置無法滿足我們在現實中的應用
現在的需求是將切割時間調整到每天的晚上 12 點,即每天切割的日誌是前一天的 0-24 點之間的內容,操作如下:
mv /etc/anacrontab /etc/anacrontab.bak //取消日誌自動輪轉的設定
使用 crontab 來作為日誌輪轉的觸發容器來修改 logrotate 預設執行時間
[root@gop-sg-192-168-56-103 logrotate.d]# vim /etc/crontab SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ # run-parts 01 * * * * root run-parts /etc/cron.hourly 59 23 * * * root run-parts /etc/cron.daily 22 4 * * 0 root run-parts /etc/cron.weekly 42 4 1 * * root run-parts /etc/cron.monthly轉載 作者:王奧OX 連結:https://www.jianshu.com/p/083b626d5129
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。