Linux日誌切割神器logroate原理介紹和配置詳解

前言

在Linux環境中能夠幫助我們分析問題蛛絲馬跡的有效辦法之一便是日誌,常見的如操作系統syslog日誌/var/log/messages,應用程序Nginx日誌/var/log/nginx/*.log。但如果服務器數量較多,日誌文件大小增長較快,不斷消耗磁盤空間就會觸發告警,如果需要人爲定期按照各種維度去手動清理日誌就顯得十分棘手。爲了節省空間和方便整理,可以將日誌文件按時間或大小分成多份,刪除時間久遠的日誌文件,這就是通常說的日誌滾動(log rotation)。logrotate(GitHub地址) 誕生於 1996/11/19 是一個Linux系統日誌的管理工具,本文會詳細介紹Linux日誌切割神器logroate的原理和配置。

Linux日誌切割神器logroate原理介紹和配置詳解

更新歷史

2019年11月05日 - 初稿

閱讀原文 - https://wsgzao.github.io/post...

擴展閱讀

man logrotate


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 里加上一條指定時間執行這個腳本的記錄,自定義週期滾動日誌就大功告成了。這種自定義的方式有兩點要注意:

  1. 配置文件裏一定要配置 rotate 文件數目這個參數。如果不配置默認是 0 個,也就是隻允許存在一份日誌,剛切分出來的日誌會馬上被刪除。多麼痛的領悟,說多了都是淚。
  2. 執行 logrotate 命令最好加 -f 參數,不然有時候配置文件修改的內容不生效。

很多程序的會用到 logrotate 滾動日誌,比如 nginx。它們安裝後,會在 /etc/logrotate.d 這個目錄下增加自己的 logrotate 的配置文件。logrotate 什麼時候執行 /etc/logrotate.d 下的配置呢?看到 /etc/logrotate.conf 裏這行,一切就不言而喻了。

include /etc/logrotate.d

logrotate原理

logrotate 是怎麼做到滾動日誌時不影響程序正常的日誌輸出呢?logrotate 提供了兩種解決方案。

  1. create
  2. copytruncate

Linux 文件操作機制

介紹一下相關的 Linux 下的文件操作機制。

Linux 文件系統裏文件和文件名的關係如下圖。

目錄也是文件,文件裏存着文件名和對應的 inode 編號。通過這個 inode 編號可以查到文件的元數據和文件內容。文件的元數據有引用計數、操作權限、擁有者 ID、創建時間、最後修改時間等等。文件件名並不在元數據裏而是在目錄文件中。因此文件改名、移動,都不會修改文件,而是修改目錄文件。

借《UNIX 環境高級編程》裏的圖說一下進程打開文件的機制。

進程每新打開一個文件,系統會分配一個新的文件描述符給這個文件。文件描述符對應着一個文件表。表裏面存着文件的狀態信息(O_APPEND/O_CREAT/O_DIRECT...)、當前文件位置和文件的 inode 信息。系統會爲每個進程創建獨立的文件描述符和文件表,不同進程是不會共用同一個文件表。正因爲如此,不同進程可以同時用不同的狀態操作同一個文件的不同位置。文件表中存的是 inode 信息而不是文件路徑,所以文件路徑發生改變不會影響文件操作。

create

這也就是默認的方案,可以通過 create 命令配置文件的權限和屬組設置;這個方案的思路是重命名原日誌文件,創建新的日誌文件。詳細步驟如下:

  1. 重命名正在輸出日誌文件,因爲重命名只修改目錄以及文件的名稱,而進程操作文件使用的是 inode,所以並不影響原程序繼續輸出日誌。
  2. 創建新的日誌文件,文件名和原日誌文件一樣,注意,此時只是文件名稱一樣,而 inode 編號不同,原程序輸出的日誌還是往原日誌文件輸出。
  3. 最後通過某些方式通知程序,重新打開日誌文件;由於重新打開日誌文件會用到文件路徑而非 inode 編號,所以打開的是新的日誌文件。

如上也就是 logrotate 的默認操作方式,也就是 mv+create 執行完之後,通知應用重新在新文件寫入即可。mv+create 成本都比較低,幾乎是原子操作,如果應用支持重新打開日誌文件,如 syslog, nginx, mysql 等,那麼這是最好的方式。

不過,有些程序並不支持這種方式,壓根沒有提供重新打開日誌的接口;而如果重啓應用程序,必然會降低可用性,爲此引入瞭如下方式。

copytruncate

該方案是把正在輸出的日誌拷 (copy) 一份出來,再清空 (trucate) 原來的日誌;詳細步驟如下:

  1. 將當前正在輸出的日誌文件複製爲目標文件,此時程序仍然將日誌輸出到原來文件中,此時,原文件名也沒有變。
  2. 清空日誌文件,原程序仍然還是輸出到預案日誌文件中,因爲清空文件只把文件的內容刪除了,而 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: 日誌文件將按月輪循。其它可用值爲dailyweekly或者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

參考文章

How To Manage Logfiles with Logrotate on Ubuntu 16.04
How to Use logrotate to Manage Log Files
Linux 日誌文件總管 ——logrotate
logrotate 機制和原理
Linux 自帶 Logrotate 日誌切割工具配置詳解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章