1.1 前言
說(shuō)出來(lái)真是丟臉,最近被公司派到客戶(hù)公司面試外包開(kāi)發(fā)崗位,本來(lái)準(zhǔn)備了什么redis、rabbitMQ、SSM框架的相關(guān)面試題以及自己做過(guò)的一些項(xiàng)目回顧,信心滿(mǎn)滿(mǎn)地去面試,結(jié)果別人一上來(lái)就問(wèn)到了最近項(xiàng)目使用的日志系統(tǒng)是什么?日志級(jí)別是怎么配置的?當(dāng)時(shí)我都蒙X了,平時(shí)都是項(xiàng)目經(jīng)理搭的,我自己也是隨便上網(wǎng)一搜往配置文件一黏貼就OK了。我就這么說(shuō)完后面試官深深定了我一眼,當(dāng)時(shí)我的內(nèi)心羞愧到......
1.2 閑話(huà)少說(shuō),講講日志的發(fā)展故事(如果已經(jīng)了解的可以跳過(guò),直接看1.3日志配置)
要想對(duì)日志技術(shù)實(shí)現(xiàn)深入了解,我個(gè)人建議去看:logback + slf4j。至于日志配置,還是了解java/276048.html">log4j比較好,因?yàn)槟壳敖^大部分的項(xiàng)目還是使用log4j的。好了,下面開(kāi)始講講日志的發(fā)展故事:
1999年,Apache開(kāi)源社區(qū)發(fā)布了log4j,一時(shí)轟動(dòng)整個(gè)程序界,從此成為日志的標(biāo)準(zhǔn)并廣泛為java程序員所使用。隨后Sun公司也在JDK1.4版本時(shí)發(fā)布了Logging機(jī)制(java.util.logging,以下簡(jiǎn)稱(chēng)JUL),但是該機(jī)制并未獲得公眾的認(rèn)可,真是可憐。不久Apache又推出了commons-logging日志框架(能夠讓開(kāi)發(fā)者抽象日志實(shí)現(xiàn)方式而不必關(guān)注具體使用哪個(gè)日志技術(shù),通俗地說(shuō)就是你要用手機(jī)叫滴滴,如果你是在北京你就會(huì)叫來(lái)北京的滴滴,在香港你就會(huì)叫來(lái)香港的滴滴),該框架仿佛是對(duì)Sun公司的鄙睨,其可以自動(dòng)查找調(diào)用當(dāng)前環(huán)境下的日志技術(shù)進(jìn)行日志輸出,該日志框架可支持log4j或JUL。commons-logging+log4j在其后的很長(zhǎng)一段時(shí)間內(nèi)成為了Java日志的經(jīng)典組合。然而之后commons-logging有一段時(shí)間沒(méi)更新了,不知道是不是commons-logging當(dāng)初的設(shè)計(jì)不夠好,想再優(yōu)化也比較多困難,為什么這么說(shuō)呢?因?yàn)榻酉聛?lái)一個(gè)優(yōu)秀的日志框架slf4j誕生了,該作者(Ceki Gülcü)就是log4j的作者之一,他的slf4j設(shè)計(jì)上更優(yōu)雅,并且他還實(shí)現(xiàn)了logback技術(shù),也是比log4j更前沿。至此,日志體系由commons-logging+log4j一家獨(dú)大的局面開(kāi)始受到動(dòng)搖,各種commons-logging+log4j?slf4j+log4j?slf4j+logback?搭配,真是讓人揪心。更恐怖的是,Ceki Gülcü大佬又幫忙優(yōu)化了log4j,從此世界又多了一項(xiàng)日志技術(shù)--log4j2。這是要學(xué)騰訊搞微信和QQ嗎,真是666。因此,如果大家想對(duì)日志技術(shù)深入了解的話(huà),可以去找找logback + slf4j的相關(guān)資料。至于配置文件,我認(rèn)為你就了解下我下面寫(xiě)的log4j配置詳解就好了,畢竟現(xiàn)在還是比較多公司用log4j框架的。
1.3 進(jìn)入正題,log4j日志基本配置
1.在項(xiàng)目的classpath下或者resource包下(maven項(xiàng)目)新建一個(gè)log4j.properties文件,初始項(xiàng)目配置如下參數(shù)就足夠了,更詳細(xì)配置可繼
續(xù)看1.4 log4j日志級(jí)別配置;
#通過(guò)根日志記錄器指定日志級(jí)別及輸出源 #日志輸出的優(yōu)先級(jí): debug < info < warn < error < fatal#定義根日志記錄器的日志級(jí)別(info)及輸出源的別名(console,myFile)#該定義讓日志在控制臺(tái)和文件輸出,并且只輸出info級(jí)別以上的日志log4j.rootLogger=info,console,myFile#######配置輸出源console的具體實(shí)現(xiàn)為控制臺(tái)輸出########定義輸出源別名console(即根日志記錄器定義的輸出源)#的實(shí)現(xiàn)類(lèi)是ConsoleAppender(控制臺(tái)輸出源)log4j.appender.console=org.apache.log4j.ConsoleAppender #指定日志輸出格式的格式轉(zhuǎn)換器為PatternLayout實(shí)現(xiàn)類(lèi)log4j.appender.console.layout=org.apache.log4j.PatternLayout#定義日志輸出的具體格式log4j.appender.console.layout.ConversionPattern=%d %-5p [%c.%M()] - %m%n #######配置輸出源myFile的具體實(shí)現(xiàn)為文件輸出########定義輸出源別名myFile(即根日志記錄器定義的輸出源)#的實(shí)現(xiàn)類(lèi)是RollingFileAppender(文件輸出源)log4j.appender.myFile=org.apache.log4j.RollingFileAppender#定義日志文件的存儲(chǔ)路徑log4j.appender.myFile.File=src/log/logProperties/log4j.log#定義日志文件的大小log4j.appender.myFile.MaxFileSize=1024kb#定義日志文件最多生成幾個(gè)(從0開(kāi)始算1個(gè),即此處最多3個(gè)文件)#超過(guò)該大小則會(huì)覆蓋前面生成的文件log4j.appender.myFile.MaxBackupIndex=2#指定日志輸出格式的格式轉(zhuǎn)換器為PatternLayout實(shí)現(xiàn)類(lèi)log4j.appender.myFile.layout=org.apache.log4j.PatternLayout#定義日志輸出的具體格式log4j.appender.console.layout.ConversionPattern=%d %-5p [%c.%M()] - %m%n #######輸出格式解釋########%d: 日志打印的時(shí)間點(diǎn),默認(rèn)格式為ISO8601,也可以另外指定格式, #定義如下: %d{yyy年MM月dd日 HH時(shí)mm分ss秒SSS},則會(huì)輸出: #2018年01月06日 14時(shí)47分45秒590#%p: 輸出日志級(jí)別,即DEBUG,INFO,WARN,ERROR,F(xiàn)ATAL #%-5p:表示字符小于5位,則字符居左(不加“-”號(hào)則字符居右),你可以舉一反三#%c: 日志所在類(lèi)的全名#%M: 日志所在方法的名字#%m: 日志信息#%n: 輸出一個(gè)回車(chē)換行符#%L: 輸出代碼中的行號(hào)
2.調(diào)用日志測(cè)試配置結(jié)果。
import org.apache.log4j.LogManager;import org.apache.log4j.Logger;import org.apache.log4j.PropertyConfigurator;public class LogPropertiesTest { public static void main(String[] args) { /*解析非classpath下的配置文件 String log4jPath=System.getProperty("user.dir")+"//src//log//logProperties//log4j.properties"; PropertyConfigurator.configure(log4jPath);*/ Logger log = LogManager.getLogger(LogPropertiesTest.class); log.debug("調(diào)試"); log.info("信息"); log.warn("警告"); log.error("錯(cuò)誤"); log.fatal("致命錯(cuò)誤"); }}
1.4日志級(jí)別配置
日志級(jí)別配置可分為3類(lèi),一類(lèi)如上配置是配置父類(lèi)日志記錄器的日志級(jí)別,第二類(lèi)是配置子類(lèi)日志記錄器的日志級(jí)別,第三類(lèi)是配置輸出源(控制臺(tái)、文件等)的日志級(jí)別。他們的日志級(jí)別解析優(yōu)先級(jí)由低到高排列。具體表述原諒我說(shuō)不清楚,直接
上案例,大家應(yīng)該能夠懂!
1.如果配置(也必須要配置)了父類(lèi)日志記錄器(rootLogger)的日志級(jí)別(假設(shè)是INFO級(jí)別),沒(méi)有配置子類(lèi)日志記錄器的日志級(jí)別,也沒(méi)有配置輸出源的日志級(jí)別,則輸出源只能輸出INFO級(jí)別以上的;
2.如果配置(也必須要配置)了父類(lèi)日志記錄器(rootLogger)的日志級(jí)別(假設(shè)是INFO級(jí)別),配置了子類(lèi)日志記錄器的日志級(jí)別(假設(shè)是DEBUG級(jí)別),沒(méi)有配置輸出源的日志級(jí)別,則輸出源輸出DEBUG級(jí)別以上的;
3.如果配置(也必須要配置)了父類(lèi)日志記錄器(rootLogger)的日志級(jí)別(假設(shè)是INFO級(jí)別),配置了子類(lèi)日志記錄器的日志級(jí)別(假設(shè)是DEBUG級(jí)別),配置了輸出源的日志級(jí)別(假設(shè)是INFO級(jí)別),則輸出源輸出INFO級(jí)別以上的;
4.如果配置(也必須要配置)了父類(lèi)日志記錄器(rootLogger)的日志級(jí)別(假設(shè)是INFO級(jí)別),沒(méi)有配置子類(lèi)日志記錄器的日志級(jí)別,配置
了輸出源的日志級(jí)別(假設(shè)是DEBUG級(jí)別),則輸出源輸出INFO級(jí)別以上的;
因此,從上述的案例中我們可以知道日志記錄器和輸出源輸出日志級(jí)別存在2個(gè)邏輯關(guān)系:
1.輸出源如果沒(méi)有定義日志級(jí)別,它會(huì)繼承最接近它的子類(lèi)日志記錄器的日志級(jí)別;子類(lèi)日志記錄器沒(méi)有定義日志級(jí)別,它會(huì)繼承最接近它的父類(lèi)日志記錄器。
2.打印日志時(shí)輸出源會(huì)根據(jù)自身定義的日志級(jí)別與最接近它的子類(lèi)日志記錄器定義的日志級(jí)別比較,如果輸出源定義的級(jí)別高于子類(lèi)日志記錄器,則按輸出源定義的日志級(jí)別輸出日志,反之則按子類(lèi)日志記錄器的日志級(jí)別輸出。
所以在項(xiàng)目中可以按日下配置方式配置日志級(jí)別:
#控制父類(lèi)日志記錄器的日志級(jí)別為info,默認(rèn)所有模塊下只輸出info級(jí)別以上的日志log4j.rootLogger=info,console#單獨(dú)控制某個(gè)模塊下的日志級(jí)別為error,只有發(fā)生異常的時(shí)候才輸出日志log4j.logger.log.logProperties=error#單獨(dú)控制某個(gè)類(lèi)的日志級(jí)別debug,方便輸出調(diào)試信息log4j.logger.log.logProperties.LogPropertiesTest=debug############# 日志輸出到控制臺(tái) ############# #日志輸出到控制臺(tái)使用的api類(lèi) log4j.appender.console=org.apache.log4j.ConsoleAppender #指定當(dāng)前輸出源的日志級(jí)別,有了前面的配置,就不需要配置該項(xiàng)了#log4j.appender.console.Threshold = info#指定日志輸出的格式:靈活的格式log4j.appender.console.layout=org.apache.log4j.PatternLayout #具體格式的內(nèi)容log4j.appender.console.layout.ConversionPattern=%d %-2p [%c.%M()] - %m%n
1.5結(jié)束語(yǔ)
到此,相信你日志配置有了基本的掌握了。文中有很多地方可能會(huì)有不對(duì)的地方,歡迎各位大俠指出。我也是為了能夠深刻理解該技術(shù)的配置,才撰文總結(jié),這樣我就會(huì)對(duì)它有更深層次的理解了。
新聞熱點(diǎn)
疑難解答
圖片精選