您好,登錄后才能下訂單哦!
這篇博文以課程課件為藍(lán)本來(lái)探討logrotate和自動(dòng)化日志處理的一系列課題,細(xì)節(jié)和深層次原理部分略有刪減,是一篇被課程耽誤了的技術(shù)博文。既然談的很直白,是一篇被課程耽誤了的技術(shù)博文,如若有打著博客做引導(dǎo)或者拿著開源工具不開源之類的討伐和道德綁架,恕不回復(fù)。
這里是分割線,不廢話了,直接切入正文,對(duì)課程有興趣,想深入理解logrotate的朋友可以關(guān)注文末課程介紹:)
日志切割是指當(dāng)應(yīng)用或系統(tǒng)的日志文件達(dá)到設(shè)定的觸發(fā)條件(如按照一定的時(shí)間周期:每天,按照大?。?00MB),對(duì)其進(jìn)行切割/分割處理,類似截?cái)嗵幚?,把原本容量比較大的日志文件“劫走”轉(zhuǎn)存為另外一個(gè)日志文件留存歸檔,這一刻之后產(chǎn)生的日志,繼續(xù)輸出到文件頭被重置為0的日志文件中。
變化的部分:日志文件的容量(瘦身變?。?,日志文件的個(gè)數(shù)(多出一份被切割下的歷史日志)
不變的部分:日志文件名不變
此外,一段時(shí)間后,我們還需要?jiǎng)h除時(shí)間久遠(yuǎn)的日志文件,整個(gè)過程也被俗稱為日志滾動(dòng)(log rotation)。
在線應(yīng)用(包括操作系統(tǒng))在長(zhǎng)期運(yùn)行過程中,會(huì)產(chǎn)生很多過程日志記錄,通常是應(yīng)用程序記錄的一些對(duì)系統(tǒng)管理員或者程序開發(fā)者有用的信息的文件,諸如正在執(zhí)行什么、發(fā)生了什么錯(cuò)誤等一系列信息。
隨著日志記錄的不斷積累,日志文件越來(lái)越大,隨著時(shí)間推移,會(huì)帶來(lái)以下弊病:
一個(gè)栗子:
日志切割的基本需求:
應(yīng)用層面
切割過程中不影響應(yīng)用的正常運(yùn)行(不能停用應(yīng)用來(lái)分割日志)
數(shù)據(jù)層面
不丟失日志,或者在可接受的范圍內(nèi)丟失極少日志
切割過程中不影響應(yīng)用繼續(xù)輸出記錄日志(日志文件名不變)
日志容量層面
切割后新的日志文件從空文件開始重新記錄(容量和文件頭被重置),便于后續(xù)查詢使用
日志歸檔層面
切割后老舊日志方便歸檔壓縮處理(文件名加上日期后綴等)
分割后的老舊日志可按照保存周期輪詢刪除
管理維護(hù)層面
自動(dòng)化周期性進(jìn)行,周而復(fù)始
從以上需求出發(fā),在滿足不停用應(yīng)用的首要前提下,可以設(shè)計(jì)出兩種日志切割的基本思路:
思路1--重命名移走舊的日志文件,同時(shí)生成一個(gè)新的日志文件(文件名與切割之前保持一致)
把現(xiàn)有日志mv成另外一個(gè)文件,同時(shí)自動(dòng)生成一個(gè)同文件名(mv之前的日志文件名)的新日志文件
日志的文件名不變,但是需要確保應(yīng)用可以指向新的文件句柄
新的日志文件當(dāng)然從0開始寫,日志文件成功瘦身!
思路2-拷貝并重命名一份現(xiàn)有日志文件,同時(shí)把現(xiàn)有容量大的日志文件內(nèi)容清空
把現(xiàn)有日志文件cp一份為另外的文件名,同時(shí)非??焖俚匕熏F(xiàn)有日志文件清空
但不改變現(xiàn)有日志文件的文件句柄(在3.1.1章節(jié)會(huì)有更多詳述)。
這樣日志文件的文件名和句柄都沒有變化,只是內(nèi)容已經(jīng)被清空,也是從0開始繼續(xù)寫入,減肥成功!
最后,需要結(jié)合定時(shí)任務(wù),周期性定時(shí)執(zhí)行日志切割任務(wù),自動(dòng)化處理
自定義腳本切割日志,核心原理是mv已有的日志文件,然后生成一個(gè)新的日志文件,結(jié)合kill
-USR1
PID 來(lái)reload應(yīng)用,以便應(yīng)用獲取新日志文件的文件句柄,日志即可輸出到新的日志文件。
注意:
-USR1 PID 僅僅是reload應(yīng)用配置,不會(huì)真正重啟應(yīng)用進(jìn)程,因此不會(huì)引起應(yīng)用停止運(yùn)行腳本切割nginx日志栗子:
#/bin/bash
bakpath='/home/nginx/logs'
logpath='/var/log/nginx/logs'
if [ ! -d $bakpath/$(date +%Y)/$(date +%m) ];then
mkdir -p $bakpath/$(date +%Y)/$(date +%m)
fi
mv $logpath/access.log $bakpath/$(date +%Y)/$(date +%m)/access-$(date +%Y%m%d%H%M).log
#給nginx發(fā)送一個(gè)信號(hào)量,讓nginx重載,重新生成新的日志文件
kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
log4j是apache針對(duì)java應(yīng)用開源的一套日志框架,java應(yīng)用可以通過加載指定的jar包,結(jié)合配置文件,從應(yīng)用本身規(guī)范日志輸出的格式,級(jí)別等,同時(shí)可附加實(shí)現(xiàn)日志的切割處理。
切割的觸發(fā)條件可以是時(shí)間周期和日志大小兩個(gè)維度。
log4j一般需要開發(fā)人員的協(xié)助,最好由開發(fā)人員直接實(shí)現(xiàn)。
linux系統(tǒng)自帶的日志處理工具,功能非常強(qiáng)大,可以進(jìn)行日志的切割,壓縮,滾動(dòng)刪除等處理。
自身基于系統(tǒng)的crontab來(lái)運(yùn)行,無(wú)需手動(dòng)配置。
cronolog開源的日志處理工具,可以實(shí)現(xiàn)自動(dòng)的按規(guī)則生成周期性的日志文件,需要單獨(dú)安裝后配置使用。
對(duì)比方案 | 部署工作量 | 對(duì)應(yīng)用的親和性 | 功能性 |
---|---|---|---|
腳本 | 前期工作量較大<br />底層邏輯都需要自己逐一實(shí)現(xiàn)<br />功能完善的腳本開發(fā)量較大 | 一般 | 看腳本本身 |
log4j | 較小,加載jar包進(jìn)行配置即可 | 好 | 較為強(qiáng)大,但不支持日志壓縮 |
第三方工具 | 較小僅僅需要配置 | 較好 | 強(qiáng)大 |
這里的第三方工具僅僅針對(duì)logrotate而言(其它工具可以參考對(duì)比因素來(lái)對(duì)比)。
選型:
多用拿來(lái)主義,避免自己重復(fù)造輪子(特指自己巴拉巴拉一股腦式寫腳本)
優(yōu)選應(yīng)用層面結(jié)合log4j方案
建議應(yīng)用層面可以應(yīng)用log4j的就應(yīng)用log4j,結(jié)合第三方工具進(jìn)行日志壓縮和周期性刪除處理
備選(次選)開源第三方工具--logrotate
不便于應(yīng)用log4j的情況下推薦使用第三方工具,尤其是logrotate,系統(tǒng)自帶,開箱即用--次選方案
操作系統(tǒng)為每一個(gè)進(jìn)程維護(hù)了一個(gè)獨(dú)立的打開文件表(fdtable),進(jìn)程每新打開一個(gè)文件,表中就會(huì)增加一個(gè)條目。
文件描述符是一個(gè)整數(shù),代表fdtable中的索引位置(下標(biāo)),指向具體的struct file(文件句柄/文件指針)
文件句柄(文件指針)對(duì)應(yīng)著文件的詳細(xì)信息,存儲(chǔ)著文件的狀態(tài)信息、偏移量和文件的inode信息等。
文件句柄中存儲(chǔ)的inode信息,對(duì)應(yīng)到應(yīng)用進(jìn)程正在寫的一個(gè)具體文件
每一個(gè)文件描述符會(huì)與一個(gè)打開的文件(文件句柄)相對(duì)應(yīng)
綜上所述,文件句柄可以唯一界定操作系統(tǒng)中一個(gè)特定的文件。
推理:
文件句柄不包括文件路徑和文件名,因此文件路徑和文件名的變化,不會(huì)引起對(duì)文件句柄的修改,進(jìn)而不會(huì)引起應(yīng)用進(jìn)程對(duì)某一特定文件(文件句柄的具體指向)的寫操作
可以通過實(shí)驗(yàn)來(lái)驗(yàn)證上述推理結(jié)論。
文件句柄的存在,決定了logrotate進(jìn)行日志切割時(shí)候,存在以下兩種方案:
- ##### 切割后使用新的文件句柄--create方式
create方式也是默認(rèn)的方案,它的核心思路是重命名原日志文件,并創(chuàng)建新的日志文件。create方案是在mv+create 執(zhí)行完之后,通知應(yīng)用重新在新的日志文件寫入即可。
那么如何通知應(yīng)用程序重新打開日志文件,從而往新的空日志文件中寫入呢?
簡(jiǎn)單粗暴的方法是殺死進(jìn)程重新打開。但是這樣會(huì)影響在線業(yè)務(wù),不可取!
于是有些程序提供了重新打開日志的接口,以Nginx為例,是通過發(fā)送USR1信號(hào)給Nginx進(jìn)程來(lái)通知Nginx重新打開日志文件的。也存在一些其他方式(如IPC),前提是程序自身要支持。
不過,有些程序并不支持create方式,壓根沒有提供重新打開日志的接口;而如果粗暴地重啟應(yīng)用程序,必然會(huì)降低可用性,為此引入了copytruncate的方案。
這個(gè)方案的思路是把正在輸出的日志拷(copy)一份出來(lái)重命名,再清空(trucate)原來(lái)的日志。從結(jié)果上看,舊的日志內(nèi)容存在滾動(dòng)的文件里,新的日志輸出到被清空的文件里。
以上兩種方案中,能用默認(rèn)的create方案就不用copytruncate,why?
數(shù)據(jù)丟失風(fēng)險(xiǎn)
這里關(guān)于create和copytruncate方式的具體執(zhí)行過程,以及注意事項(xiàng),包含了較為關(guān)鍵的技術(shù)細(xì)節(jié)。如若以上描述不足以理解,可以關(guān)注課程https://edu.51cto.com/sd/3f309, 接受免費(fèi)試看。
logrotate自身已經(jīng)被集成到系統(tǒng)定時(shí)任務(wù)中,基于CRON來(lái)運(yùn)行,默認(rèn)每天運(yùn)行一次。
定時(shí)任務(wù):
/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
要點(diǎn):
/usr/sbin/logrotate 執(zhí)行文件
-s /var/lib/logrotate/logrotate.status 記錄執(zhí)行后的狀態(tài)
/etc/logrotate.conf 運(yùn)行時(shí)加載的配置文件
問題: cron.daily究竟是在每天什么時(shí)間執(zhí)行的呢?
Logrotate是基于CRON運(yùn)行的,所以這個(gè)時(shí)間是由CRON控制的,具體可以查詢CRON的配置文件/etc/anacrontab(老版本的文件是/etc/crontab)
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 #這個(gè)是隨機(jī)的延遲時(shí)間,表示最大45分鐘
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22 #這個(gè)是開始時(shí)間段,3點(diǎn)-22點(diǎn)
#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
1 5 cron.daily
第一個(gè)是Recurrence period 第二個(gè)是延遲時(shí)間(the base delay,基本的延遲時(shí)間)
總的延遲時(shí)差是:基本延遲+隨機(jī)延遲=5~(5+45),即5-50 min
開始的基準(zhǔn)時(shí)間:3-22點(diǎn),不出意外,就是3點(diǎn)開始
所以cron.daily會(huì)在3:00+(5,50)這個(gè)時(shí)間段執(zhí)行
定時(shí)任務(wù)執(zhí)行時(shí)間,也可以通過日志和處理過的日志文件兩種方式來(lái)確認(rèn)。
logrotate自動(dòng)化處理日志的過程如下:
Redhat系列系統(tǒng)缺省的cron 在每天的3:00+(5,50)這個(gè)時(shí)間段喚醒觸發(fā)cron.daily下定義的logrotate定時(shí)任務(wù)
logrotate加載默認(rèn)的配置文件/etc/logrotate.conf,定位判斷需要被處理的日志文件
基于配置文件的相關(guān)參數(shù),對(duì)匹配到的日志文件執(zhí)行日志切割、壓縮、轉(zhuǎn)儲(chǔ)即周期性刪除處理
完成后產(chǎn)生過程狀態(tài)記錄文件 /var/lib/logrotate/logrotate.status
實(shí)戰(zhàn)運(yùn)用中,我們是先設(shè)置好logrotate的相關(guān)參數(shù)和任務(wù),然后等待cron來(lái)喚醒定時(shí)任務(wù)觸發(fā)執(zhí)行。
注意:
理解了原理過程,我們?cè)賮?lái)梳理一下logrotate的配置文件。配置文件分為全局默認(rèn)配置/etc/logrotate.conf和/etc/logrotate.d目錄下的自定義配置。
配置的有效性和優(yōu)先級(jí):
logrotate加載配置時(shí),會(huì)針對(duì)/etc/logrotate.d目錄下的每個(gè)自定義配置,與全局默認(rèn)配置/etc/logrotate.conf進(jìn)行合并渲染,如存在相同項(xiàng)或者沖突項(xiàng),以自定義配置為準(zhǔn):
相同項(xiàng):
? 全局配置和自定義配置中配置了相同的參數(shù)key,但value不同的情況
沖突項(xiàng):
? 全局配置和自定義配置中存在的沖突項(xiàng)
全局配置文件:
cat /etc/logrotate.conf
# see "man logrotate" for details
# rotate log files weekly
weekly #每周輪轉(zhuǎn)一次
# keep 4 weeks worth of backlogs
rotate 4 #保留四個(gè)被切割轉(zhuǎn)儲(chǔ)后的日志文件(即備份的老日志文件)
# create new (empty) log files after rotating old ones
create #rotate后,創(chuàng)建一個(gè)新的空文件,默認(rèn)的create方式處理
# use date as a suffix of the rotated file
dateext # 日志文件切割時(shí)添加日期后綴,后綴格式Y(jié)YYYmmdd,切割后的文件名如xxx.log-20200202
# uncomment this if you want your log files compressed
#compress #默認(rèn)切割轉(zhuǎn)儲(chǔ)后的日志是不壓縮的
# RPM packages drop log rotation information into this directory
include /etc/logrotate.d #編程中常用的include大法,該目錄下的配置文件都會(huì)被引用生效
# no packages own wtmp and btmp -- we'll rotate them here #順帶rorate兩個(gè)孤兒日志
/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.
默認(rèn)配置文件中已經(jīng)通過include /etc/logrotate.d大法指明了自定義配置文件的路徑,因此在這個(gè)路徑下定義細(xì)化配置即可。
例1: create方式切割nginx日志
cat /etc/logrotate.d/nginx
/var/log/nginx/*.log { # 可以指定多個(gè)路徑,多個(gè)路徑通過空格或換行符分隔,支持正則匹配
daily # 日志輪詢周期,weekly,monthly,yearly
rotate 30 # 留存30份切割后的舊日志,以天為周期,即保存30天舊日志,超過則刪除
size +100M # 超過100M時(shí)分割,單位k,M,G,優(yōu)先級(jí)高于daily
compress # 切割后立即對(duì)老日志進(jìn)行g(shù)zip壓縮,也可以為nocompress
dateext # 日志文件切割時(shí)添加日期后綴
missingok # 如果沒有日志文件也不報(bào)錯(cuò)
notifempty # 日志為空時(shí)不進(jìn)行切換,默認(rèn)為ifempty
create 640 nginx nginx # 使用該模式創(chuàng)建新的空日志文件,mode,user和group參數(shù)可以省略
sharedscripts # 所有的文件切割之后再一次性執(zhí)行下面腳本
postrotate
if [ -f /var/run/nginx.pid ]; then #腳本符合shell語(yǔ)法和邏輯即可
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
其它較為常用的配置參數(shù):
nocopytruncate copy日志文件后不截?cái)嗖磺蹇杖罩荆瑑H僅備份用
nocreate 不建立新的日志文件,用于僅僅只需要對(duì)應(yīng)用日志進(jìn)行壓縮和輪詢刪除的場(chǎng)景
errors address 遇到錯(cuò)誤時(shí)信息發(fā)送到指定的Email 地址
olddir directory 轉(zhuǎn)儲(chǔ)后的日志文件放入指定的目錄,必須和當(dāng)前日志文件在同一個(gè)文件系統(tǒng)
prerotate 在logrotate轉(zhuǎn)儲(chǔ)之前需要執(zhí)行的指令,例如創(chuàng)建一個(gè)轉(zhuǎn)儲(chǔ)的日志目錄
rotate count 指定日志文件刪除之前轉(zhuǎn)儲(chǔ)的次數(shù)(個(gè)數(shù)),0指沒有備份,5指保留5個(gè)備份
maxage 以單個(gè)轉(zhuǎn)儲(chǔ)時(shí)間周期為計(jì)數(shù)單位來(lái)保留老舊日志,如每天處理,代表保留多少天的老舊
日志,此時(shí)與rotate count無(wú)區(qū)別
dateext 使用當(dāng)期日期-YYYYmmdd作為轉(zhuǎn)儲(chǔ)后的日志文件附加后綴,不配置則以數(shù)字1到n作為后
綴,n為rotate n中的配置參數(shù)
dateformat .%s 配合dateext使用,緊跟在下一行出現(xiàn),定義文件切割后的文件名附加后綴,必須配合
dateext使用,只支持 %Y %m %d %s 這四個(gè)參數(shù)
其它可參照man文檔,以及/etc/logrotate.d/下系統(tǒng)自帶的配置文件來(lái)研究。
注意事項(xiàng):
logrotate本身是通過系統(tǒng)定時(shí)任務(wù)cron來(lái)在每天的凌晨3-4點(diǎn)之間某個(gè)時(shí)間點(diǎn)觸發(fā),至于logrotate它自己被觸發(fā)后,會(huì)不會(huì)對(duì)我們指定的日志文件進(jìn)行預(yù)期的切割處理,還取決于我們對(duì)logrotate執(zhí)行動(dòng)作的條件約束,更多細(xì)節(jié)可以關(guān)注課程https://edu.51cto.com/sd/3f309, 接受免費(fèi)試看。
應(yīng)用舉例:
cat /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 60
compress
notifempty
dateext
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ];then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
copytruncate方式切割tomcat catalina.out日志
注意事項(xiàng):
以上是典型的生產(chǎn)環(huán)境應(yīng)用舉例,配置層面本身不難,重要的地方在于實(shí)際運(yùn)用后會(huì)發(fā)現(xiàn)并非一切如預(yù)期所愿,需要掌握必要的技巧才能用好。細(xì)節(jié)部分可以關(guān)注課程https://edu.51cto.com/sd/3f309, 接受免費(fèi)試看。
實(shí)際在生產(chǎn)環(huán)境運(yùn)用中,還存在一些高階技巧需要掌握,甚至說(shuō)部分地方存在一些坑需要我們明確并避開它們。這里列舉一些典型的情況,感興趣的朋友可以關(guān)注課程https://edu.51cto.com/sd/3f309, 接受免費(fèi)試看,相信您會(huì)有不一樣的收獲。
copytruncate的原理決定了理論上分析,日志丟失不可避免。
日志丟失的程度參考:
https://incoherency.co.uk/blog/stories/logrotate-copytruncate-race-condition.html
I wrote a small C program to test it (outputting increasing numbers as fast as it could) and, indeed, 4 million lines were lost during the course of the log rotation.
要么規(guī)避,要么解決。
基于自己對(duì)logrotate的理解和生產(chǎn)環(huán)境實(shí)際運(yùn)用的一些經(jīng)歷,發(fā)現(xiàn)有些看似簡(jiǎn)單和當(dāng)然的過程,實(shí)際都有非常強(qiáng)的原理和邏輯來(lái)支撐。因此萌生了對(duì)他們有一個(gè)系統(tǒng)的梳理總結(jié)的想法,最后想著還是以課程分享輸出,搗鼓一陣,在原來(lái)的構(gòu)想基礎(chǔ)上,增加了一些概念性和原理性的輸出,近期算是上架了。
課程合計(jì)無(wú)限接近5小時(shí),還是有一定的成本。主要的部分摘取在這里了,章節(jié)設(shè)計(jì)原汁原味,一方面有一定基礎(chǔ)且結(jié)合文章能領(lǐng)會(huì)略去細(xì)節(jié)的朋友,閱讀之后相信依然會(huì)有所收獲,不妨礙他們對(duì)logrotate的進(jìn)一步理解,另一方面,如若領(lǐng)會(huì)這篇文章略有難度,也可以考慮關(guān)注一下課程,無(wú)限接近5小時(shí)課程一份盒飯的價(jià)格,從概念到原理,從配置講解到實(shí)戰(zhàn)運(yùn)用,以及生產(chǎn)環(huán)境下應(yīng)用的高階技巧、避坑指南等,一籃子設(shè)計(jì),相信您會(huì)有不一樣的收獲。
課程以logrotate為主線,突出實(shí)戰(zhàn)應(yīng)用性,全面深入講解自動(dòng)化處理應(yīng)用日志的方方面面(包括日志切割/日志輪詢、日志壓縮、日志周期性刪除等),傳授整套自動(dòng)化處理日志的知識(shí)體系。
課程大綱,有圖有真相:
課程鏈接:https://edu.51cto.com/sd/3f309
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。