java?log?is判斷引發(fā)的一系列事件解析
序
首先來源是 老大code Review的時候 說到日志,讓我從 log.debug 加上一個if 判斷,log.isDebug ,這一聽就想到是 為了防止debug 日志不打印,導(dǎo)致的String拼接等 沒必要的損耗
嗯嗯 老大說的確實(shí)有道理,改吧
我靠,這一查幾百個 log 需要加,這一個一個改也太累了
總 需求列表
- log 自動加上if判斷 如果外面有if判斷了,忽略
- 最后 寫了個idea 插件。。。。
log 自動加上if判斷 調(diào)研
剛上來,我先百度下 是不是有現(xiàn)成的,我現(xiàn)在用的lombok,按道理應(yīng)該有一個屬性 控制 是否加if的,嗯嗯 沒錯,找找,我一般先看看 @Sl4J 給我提供了什么參數(shù)配置
@Retention( RetentionPolicy . SOURCE ) @Target({ElementType.TYPE}) public @interface Slf4j{ String topic() default }
思考 這個topic干什么的???
說實(shí)話 我之前沒有用過這個屬性。。。。狗頭。。
@Slf4j 注解有個topic 屬性可以進(jìn)行設(shè)置要采用的logger,
topic 的值對應(yīng)的就是logback.xml中定的logger name。root logger是默認(rèn)就存在的。
到這 你可能要問了,root logger 是默認(rèn)實(shí)現(xiàn),你說是默認(rèn)實(shí)現(xiàn)就是默認(rèn)實(shí)現(xiàn)了? 證據(jù)呢?
對應(yīng)的啟動Config類為 ch.qos.logback.classic.BasicConfigurator
嗯嗯 根上是ROOT
有一個細(xì)節(jié),我們在配置logback.xml的時候 都會寫這種
<logger name="com" level="DEBUG" > <appender-ref ref="STDOUT"/> </logger> <logger name="com.example.demo" level="warn" > <appender-ref ref="STDOUT"/> </logger>
你是不是好奇 這種的name怎么解析的?
他是從頭開始 遍歷包名 從loggerCache 中看看是否有匹配的,一層層找
思考
不說這些理論了,一句話 按照上面配置 logback.xml 在 com.example.demo.controller 下的類執(zhí)行會打印log.info日志么?
@RestController @RequestMapping @Slf4j public class DemoController { @RequestMapping("/test") public String test(){ log.info("sad"); return "success"; } }
嗯嗯 這么一實(shí)驗(yàn) 沒打印啊
有人可能問了,那把2個logger 順序反過來? 不用試了,也不行
這一看 com.example.demo的warn生效了啊,debug/info 都沒打印出來,那為什么呢?
先看一個圖
下面就要看下 這個children 當(dāng)時怎么賦值的了 其實(shí)就是從 最底下 往上找,在這里找到了 com.example.demo 的配置并且應(yīng)用,是因?yàn)?logger類中
int h; do { h = LoggerNameUtil.getSeparatorIndexOf(name, i); String childName; if (h == -1) { childName = name; } else { childName = name.substring(0, h); } i = h + 1; synchronized(logger) { childLogger = logger.getChildByName(childName); if (childLogger == null) { childLogger = logger.createChildByName(childName); this.loggerCache.put(childName, childLogger); this.incSize(); } } logger = childLogger; } while(h != -1);
一直找到最后,返回的就是最后/最靠近 目標(biāo)類的logger 配置
小結(jié)
logger 配置不是按照pom.xml的那種優(yōu)先順序,而是包名匹配 最多的生效,如果你發(fā)現(xiàn) 日志打印和你想的不一樣,你可以去看下 LoggerContext 類中 loggerCache 屬性的值,檢查下
如果是一個業(yè)務(wù)系統(tǒng),可能是一種logback.xml模板,如果你是中間件/組件,就需要對logback.xml 進(jìn)行改動了,因?yàn)橹虚g件可能是 binlog監(jiān)聽等等 大數(shù)據(jù)量的,如果按照業(yè)務(wù)系統(tǒng)那種搞法 有的日志是沒必要,根據(jù)你的業(yè)務(wù) 請自由配置
說回來 lombok 到底有沒有自動加if的插件啊
lombok @Sl4j 是沒有了,百度下吧
好吧,這也什么都沒有,官網(wǎng)看看,哎 也沒有,按道理應(yīng)該有啊,也不難。。。
我突然在想是不是這個優(yōu)化 也不像我們想的那么有優(yōu)化效果,肯定還是有必要的
log isDebug 判斷的必要性
錯誤案例
現(xiàn)象描述:發(fā)現(xiàn)某些服務(wù)器的pv數(shù)不高,但服務(wù)器的load卻不低,高于平均水平
錯誤分析
分析過程: 通過內(nèi)存監(jiān)控發(fā)現(xiàn),GC的動作比較頻繁,但無法找到原因,一次PLA偶然的發(fā)現(xiàn)了大量如log.debug(“memberId:” + member.getMemberId())代碼
原因分析
在代碼中發(fā)現(xiàn)如下代碼段很多: log.debug(“memberId:” + member.getMemberId())
以上代碼執(zhí)行時,分兩步:
- 先執(zhí)行的是括號中的字符串相”+”的動作,而每次”+”運(yùn)算都會導(dǎo)致新字符串的生成,這樣就產(chǎn)生了很多“中間字符串”,在極大次數(shù)被調(diào)用時,這種字符串被創(chuàng)建和銷毀的數(shù)量非常龐大,從而造成了jvm gc頻繁執(zhí)行,進(jìn)而影響了性能。
- 再執(zhí)行l(wèi)og.debug()函數(shù),在生產(chǎn)環(huán)境log level一般大于info,所以實(shí)際不會打印debug信息綜上所述,這些代碼在生產(chǎn)環(huán)境不會產(chǎn)生日志,但會執(zhí)行字符串”+”運(yùn)算,而這些運(yùn)算是無意義的,所以需要先判斷日志的優(yōu)先級,方式是log.isXXXEnabled() { log.XXX(……); }
Log Level的級別: Fatal->error->warn->info->debug,級別從高到低 一般我們生成環(huán)境的log level都是error,所以對于Error以上級別的日志,不用判斷;對于error以下級別的都要加上判斷。
總結(jié)
is 判斷還是有必要的,目前沒什么別的辦法,我在寫一個idea 插件,來一個按鈕/快捷鍵 自動添加log if判斷,正好玩玩
后續(xù)
行吧,既然說了做一個idea 插件,搞起來,周末花了幾個小時搞了一版,提交了idea 審核 ,等待審核中 起名叫java-tools 開發(fā)會用的功能 我會迭代進(jìn)去,有什么是你們需要的可以評論下,我會排下優(yōu)先級 開發(fā)
簡單效果:
@Slf4j public class A { public void a(){ log.info("21") ; } }
點(diǎn)擊 ctrl + 8 一起按 或者 右鍵
變?yōu)?/p>
@Slf4j public class A { public void a(){ if(log. isInfoEnabled()){ log. info("21"); } } }
以上就是java log is判斷引發(fā)的一系列事件解析的詳細(xì)內(nèi)容,更多關(guān)于log is判斷引發(fā)事件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JAVA多線程實(shí)現(xiàn)生產(chǎn)者消費(fèi)者的實(shí)例詳解
這篇文章主要介紹了JAVA多線程實(shí)現(xiàn)生產(chǎn)者消費(fèi)者的實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06Intellij IDEA導(dǎo)入eclipse web項(xiàng)目的操作步驟詳解
Eclipse當(dāng)中的web項(xiàng)目都會有這兩個文件,但是idea當(dāng)中應(yīng)該是沒有的,所以導(dǎo)入會出現(xiàn)兼容問題,但是本篇文章會教大家如何導(dǎo)入,并且導(dǎo)入過后還能使用tomcat運(yùn)行,需要的朋友可以參考下2023-08-08java簡單實(shí)現(xiàn)復(fù)制 粘貼 剪切功能代碼分享
本文給大家分享了一段java編寫的簡單實(shí)現(xiàn)復(fù)制粘貼剪切功能的代碼,需要的小伙伴可以直接拿走使用。如有更好的方案,也可以告之本人。2014-11-11SpringBoot實(shí)現(xiàn)IP地址解析的示例代碼
本篇帶大家實(shí)踐在springboot項(xiàng)目中獲取請求的ip與詳細(xì)地址,我們的很多網(wǎng)站app中都已經(jīng)新增了ip地址顯示,具有一定的參考價值,感興趣的可以了解一下2024-01-01SpringBoot+Response如何統(tǒng)一返回result結(jié)果集
這篇文章主要介紹了SpringBoot+Response如何統(tǒng)一返回result結(jié)果集,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05java獲取登錄者IP和登錄時間的兩種實(shí)現(xiàn)代碼詳解
這篇文章主要介紹了java獲取登錄者IP和登錄時間的實(shí)現(xiàn)代碼,本文通過兩種結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07Java Code Cache滿導(dǎo)致應(yīng)用性能降低問題解決
這篇文章主要介紹了Java Code Cache滿導(dǎo)致應(yīng)用性能降低問題解決,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08