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