Nginx 日誌分割
nginx 默認沒有提供對日誌文件的分割功能,所以隨着時間的增長,access.log 和 error.log 文件會越來越大,尤其是 access.log,其日誌記錄量比較大,更容易增長文件大小。影響日誌寫入性能分割 nginx 日誌的方法有很多,這裏推薦利用 Logrotate 來完成。
Logrotate 用法
1. 安裝
logrotate 是一個 Linux 系統日誌的管理工具。可以對單個日誌文件或者某個目錄下的文件按時間 / 大小進行切割,壓縮操作;指定日誌保存數量;還可以在切割之後運行自定義命令。
logrotate 是基於 crontab 運行的,所以這個時間點是由 crontab 控制的,具體可以查詢 crontab 的配置文件 /etc/anacrontab。系統會按照計劃的頻率運行 logrotate,通常是每天。在大多數的 Linux 發行版本上,計劃每天運行的腳本位於 /etc/cron.daily/logrotate。
主流 Linux 發行版上都默認安裝有 logrotate 包,如果你的 Linux 系統中找不到 logrotate, 可以使用 apt-get 或 yum 命令來安裝。
yum install -y logrotate
一般 Linux 都已經自帶 logrotate,下列命令可以查看是否已安裝。
rpm -ql logrotate
2. 基本用法詳解
2.1 入門
/etc/logrotate.conf 這個文件是 logrotate 的主配置文件。
# 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
# 包含自定義配置目錄
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.
這個主配置文件中定義了日誌文件分割的通用參數。並且 include /etc/logrotate.d 表示其會加載 /etc/logrotate.d 的所有自定義配置文件,自定義配置文件中的配置可以覆蓋掉通用配置。
我們來到自定義配置文件的目錄 / etc/logrotate.d。
嘗試在該目錄中創建一個日誌分割配置 test,對 /opt/logtest 目錄中所有以 .log 結尾的文件進行分割。
vim test
# test配置文件的內容
/opt/logtest/*.log {
daily
rotate 2
copytruncate
missingok
}
test 配置的第一行指定要對哪個路徑的哪些文件進行分割,然後攜帶的 4 個參數解釋如下:
-
daily:按天切割。觸發切割時如果時間不到一天不會執行切割。除了 daily,還可以選 monthly,weekly,yearly;
-
rotate:對於同一個日誌文件切割後最多保留的文件個數;
-
copytruncate:將源日誌文件切割成新文件後,清空並保留源日誌文件。默認如果不啓用該配置,分割後源日誌文件將被刪除。設置該值,以便分割後可以繼續在源日誌文件寫入日誌,等待下次分割;
-
missingok:切割中遇到日誌錯誤忽略。
創建好配置以後,系統會在每天利用 cron 定時執行 logrotate 日誌分割指令。這裏我們爲了看到效果,不等到系統自動執行,可以手動強制執行一次日誌分割。強制執行會立即進行一次日誌。
# -v:顯示執行日誌
# -f:強制執行分割
logrotate -vf /etc/logrotate.d/test
執行前,事先在日誌所在目錄中創建 2 個測試日誌文件。
touch test1.log
touch test2.log
手動執行一次日誌分割,觀察執行日誌可以發現,過程如下:
-
先將源日誌內容拷貝到分割後的文件
-
清空源文件
此時分割後的文件名爲源文件名後面加上 . 序號,序號從 1 開始。
然後我們再次手動執行一次分割,此時執行過程如下:
-
將第一次分割後的日誌文件 test1.log.1 重命名爲 test1.log.2;
-
將源日誌文件拷貝到此次分割後的文件,命名序號重新從 1 開始,爲 test1.log.1;
-
清空源日誌文件。
接着再次手動執行一次分割,此時執行過程如下:
-
將之前分割後的日誌文件 test1.log.2 重命名爲 test1.log.3,test1.log.1 重命名爲 test1.log.2;
-
分割源日誌文件,拷貝其內容到 test1.log.1;
-
由於設置了 rotate 爲 2,即最多保留 2 個日誌文件,所以此時要刪除最早分割出的那個日誌文件,即 test1.log.3。
總結一下 logrotate 日誌分割的步驟:
-
默認分割後日志的命名爲源日誌名稱 +. 序號(從 1 開始)。分割之前將所有之前分割出的日誌文件重命名,序號往後移一位;
-
執行分割,將源日誌文件分割爲源日誌文件名 .1。這樣就保證了所有分割後的文件中,序號最小的是最新分割出的,序號最大的是最早分割出的;
-
根據 rotate 設置,如果此次分割後文件數量大於 rotate 設置,那麼刪除序號最大的那個分割文件,也就是最舊的分割日誌。
實際開發中可以使用 create 代替 copytruncate,它們的區別如下:
-
copytruncate 先將源文件內容拷貝到分割後文件,再清空源文件,拷貝和清空之間有時間差,可能會丟失部分日誌。另外拷貝操作在源文件比較大時消耗性能;
-
create 直接將源文件重命名爲分割後文件,再創建一個與源文件名稱相同的新文件,用於後續日誌寫入。
/opt/logtest/*.log {
daily
rotate 2
create # 創建與源文件名稱相同的新文件,用於後續日誌寫入,新文件的歸屬用戶、權限與源文件相同
missingok
}
但是要注意 create 即使創建新的文件後,如果沒有主動通知應用程序,那麼應用程序仍然會往舊的文件 (即被重命名的那個分割後的文件) 寫入日誌。所以此時在分割後要通知應用程序重新打開新的日誌文件進行寫入。
以通知 nginx 爲例,配置如下:
/var/log/nginx/*.log {
daily
rotate 30
create
sharedscripts # 所有的文件切割之後只執行一次下面腳本,通知nginx重新打開新的日誌文件進行後續寫入
postrotate
if [ -f /run/nginx.pid ]; then
kill -USR1 `cat /run/nginx.pid` # 通過USER1信號通知nginx重新打開日誌文件
fi
endscript
}
綜上,一般情況下如果應用程序提供了通知其打開新的日誌文件的接口,那麼推薦使用 create 續寫日誌;否則推薦使用 copytruncate 續寫日誌。
注意:
-
/etc/logrotate.d 中的自定義配置中,如果不配置 rotate、daily 等參數在強制手動執行時並不會繼承默認的主配置 /etc/logrotate.conf。比如不配置 rotate 時,並不會繼承保留 4 個分割文件,而是等價於 0,即不保留任何分割文件。所以自定義配置中推薦顯式指定這些參數;
-
在系統 crontab 定時任務自動執行 logrotate 時,自定義配置會繼承主配置文件中的參數;
-
logrotate 執行分割的時機要依賴於 crontab 定時任務,也就是說 crontab 定時任務每日觸發時,logrotate 纔會讀取相應配置,檢查是否滿足分割的條件決定是否執行分割。這意味着,在默認 crontab 每日觸發 logrotate 的定時任務情況下,即便 logrotate 配置文件中配置的分割頻率小於 1 天,也將按照 1 天的頻率觸發分割,除非修改 crontab 定時任務,將 logrotate 的任務觸發頻率修改爲小於 1 天。
2.2 分割文件壓縮
我們可以通過如下設置對分割後的日誌文件開啓壓縮:
/opt/logtest/*.log {
daily
rotate 2
copytruncate
missingok
compress # 以gzip方式壓縮
nodelaycompress # 所有分割後的文件都進行壓縮
}
此時刪除原有所有文件,重新創建測試日誌文件 test1.log 和 test2.log,然後手動執行分割,可以生成壓縮後的 .gz 文件。
一般可以將 nodelaycompress 改爲 delaycompress,這樣分割後對最新的序號爲 1 的文件不會進行壓縮,對其他序號的文件進行壓縮,這樣可以方便我們查看最新的分割日誌。
2.3 按照時間分割
按照時間分割可以定時分割出一個日誌,比如每天分割一次,配合其他參數可以完成保留最近 n 天日誌的功能。以下配置可以實現每天分割一次日誌,並且保留最近 30 天的分割日誌。
/opt/logtest/*.log {
daily # 每天分割一次
rotate 30 # 保留最近30個分割後的日誌文件
copytruncate
missingok
dateext # 切割後的文件添加日期作爲後綴
dateyesterday # 配合dateext使用,添加前一天的日期作爲分割後日志的後綴
}
還是先刪除原來的所有文件,重新創建。
touch test{1,2}.log
再手動執行分割,此時生成的分割後的文件將不再以序號作爲文件名結尾,而是以昨天的日期作爲結尾。
並且如果馬上再手動執行一次分割,由於日期相同,不會像原來一樣生成序號遞增的新日誌文件,此時相當於沒有執行任何分割操作。即同一天只能分割一次,第二天再次執行纔會分割出新的日期結尾的文件,所以此時設置 rotate 的值即爲保留最近多少天日誌的意思。
此外,默認添加的日期後綴格式爲 yyyyMMdd,可以用 dateformat 自定義。
/opt/logtest/*.log {
daily # 每天分割一次
rotate 30 # 保留最近30個分割後的日誌文件
copytruncate
missingok
dateext # 切割後的文件添加日期作爲後綴
dateyesterday # 配合dateext使用,添加前一天的日期作爲分割後日志的後綴
dateformat -%Y-%m-%d # 格式爲2022-02-08
}
2.4 按照文件大小分割
我們可以利用 size 配置指定當日誌文件達到多大體積時才進行分割。以下配置指定了每天執行分割,但是隻有當日誌文件大於 5M 時才真正執行分割操作。
/opt/logtest/*.log {
daily # 每天分割一次
size 5M # 源文件小於5M時不分割
rotate 30 # 保留最近30個分割後的日誌文件
create
missingok
dateext # 切割後的文件添加日期作爲後綴
dateyesterday # 配合dateext使用,添加前一天的日期作爲分割後日志的後綴
}
注意:這個配置並不是說日誌文件達到指定大小就自動執行分割,它還是要遵循定時任務。比如配置了 daily 只有到每天指定時間執行分割任務時,纔會檢查文件大小,對超過指定大小的文件進行分割。
2.5 自定義每小時分割
logrotate 實現每日定時執行日誌分割的原理是通過 cron 定時任務,默認在 /etc/cron.daily 中包含 logrotate 可執行命令,所以系統每天會定時啓動 logrotate,然後它會根據配置中具體分割頻率(daily、weekly 等)以及其他條件(比如 size)決定是否要真正執行分割操作。
如果我們想要實現每小時進行一次分割,需要如下步驟:
-
logrotate 配置文件中指定分割頻率爲 hourly;
-
配置完以後,還需要在 cron 的每小時定時任務中加入 logrotate,因爲默認情況下只有 /etc/cron.daily 中包含 logrotate 可執行命令,我們要將它往 /etc/cron.hourly 中也拷貝一份,這樣系統纔會每小時調用一次 logrotate 去執行分割。
cp /etc/cron.daily/logrotate /etc/cron.hourly/
2.6 自定義分割執行時間
logrotate 是基於 cron 運行的,所以這個時間是由 cron 控制的,具體可以查詢 cron 的配置文件 /etc/crontab 。舊版 CentOS 的 cron 的配置文件是 /etc/crontab ,新版 CentOS 改爲 /etc/anacrontab。
從上面的內容可以看出:
-
如果機器 沒有關機,默認 logrotate(配置文件裏設置的是 cron.daily)一般會在每天的 3 點 05 分到 3 點 50 分之間執行, 真實的延遲時間是 RANDOM_DELAY + delay in minute;
-
如果在 3-22 這個時間段內服務器處於 關機狀態,則 logrotate 會在機器開機 5 分鐘後執行分割日誌的操作。
如果我們覺得每天凌晨 3 點多執行日誌分割不合適,那麼可以自定義分割執行時間。實現方式可以是:
-
修改 /etc/anacrontab 中的定時執行時間,實際不推薦,可能會影響系統其他定時任務;
-
在 /etc/logrotate.d 以外的其他目錄創建 logrotate 配置文件,然後利用 crontab 自定義 cron 表達式來執行 logrotate 對該配置進行分割操作。
推薦採用 crontab 方式自定義執行時間,步驟如下:
-
在非 /etc/logrotate.d 目錄創建 logrotate 配置文件,這是爲了避免被系統的定時任務掃描到該配置而導致重複執行分割。
-
添加 crontab 計劃任務,在 root 用戶下執行 crontab -e 進入 vim 模式,進行編輯。
crontab -e
# 每天 23點59分進行日誌切割
59 23 * * * /usr/sbin/logrotate -f /etc/logrotate_mytime/nginx
- 重啓 crontab。
# centos6:
service crond restart
# centos7:
systemctl restart crond
nginx 日誌分割步驟
在 /etc/logrotate.d 中創建文件 nginx,作爲 nginx 日誌分割的配置文件。指定每天執行一次分割,並且當文件大於 5M 時才進行分割。同時指定 notifempty,當日志文件爲空時不分割。
/opt/docker-ws/nginx/logs/*.log {
daily # 每天分割一次
size 5M # 源文件小於5M時不分割
rotate 30 # 保留最近30個分割後的日誌文件
copytruncate
notifempty # 當日志文件爲空時不分割
missingok
dateext # 切割後的文件添加日期作爲後綴
}
這樣配置了以後系統會在凌晨 3 點多執行分割操作,執行結果會保存到 /var/spool/mail/root 中。
查看結果發現提示權限不夠而分割失敗,這是因爲開啓了 selinux 導致,解決方案有如下 2 種:
-
關閉 selinux
-
利用 semanage 修改待分割的日誌文件所在目錄的權限
# 開放/opt/logtest目錄的權限
semanage fcontext -a -t var_log_t "/opt/logtest(/.*)?"
restorecon -Rv /opt/logtest
轉自: 包包,
鏈接:https://baobao555.tech/archives/57
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/lyUn318LhEdORzTr40gUgA