slf4j沒有魔法。有記錄的問題曾經是,如果你想登錄假設
logger.debug("expensive string representation: " + godObject)
那麼無論是否調試級別是在記錄器啓用與否,你總是評估godObject.toString()
它可以是一個昂貴的操作,然後也是字符串連接。這是因爲Java(和大多數語言)參數在傳遞給函數之前進行了評估。
這就是爲什麼slf4j引入logger.debug(String msg, Object arg)
(和其他變體的更多參數)。整個想法是,您將便宜的參數傳遞給debug
函數,並在它們上調用toString
,並且只有在調試級別打開時纔將它們組合成消息。
注意,通過調用
logger.debug("expensive string representation, eg: {}", godObject.toString());
你大大減少這種優勢,因爲這樣你轉換godObject
所有的時間,你把它傳遞給debug
之前,無論水平上什麼調試。你只
logger.debug("expensive string representation, eg: {}", godObject);
應該用然而,這仍然不理想。它只保留調用toString
和字符串連接。但是,如果您的日誌消息需要其他昂貴的處理來創建消息,它將無濟於事。就像如果你需要調用一些expensiveMethod
創建消息:
logger.debug("expensive method, eg: {}",
godObject.expensiveMethod());
然後expensiveMethod
被傳遞到logger
之前總是被判斷。爲了使這項工作有效地與SLF4J,你仍然不得不求助於回
if (logger.isDebugEnabled())
logger.debug("expensive method, eg: {}",
godObject.expensiveMethod());
Scala的呼叫按姓名有很大幫助,在這個問題上,因爲它可以讓你的代碼中的任意一塊封裝成函數對象和僅在需要時才評估該代碼。這正是我們需要的。例如,讓我們看看slf4s。該庫公開像
def debug(msg: => String) { ... }
方法爲什麼沒有參數像SLF4J的Logger
?因爲我們不再需要它們了。我們可以只寫
logger.debug("expensive representation, eg: " +
godObject.expensiveMethod())
我們沒有傳遞消息及其參數,我們直接傳遞了一條評估消息的代碼。但只有在記錄儀決定這麼做的時候。如果調試級別沒有打開,那麼logger.debug(...)
內的任何內容都不會被評估,整個事情就會被忽略。既不調用expensiveMethod
也不調用任何toString
調用或字符串串聯。所以這種方法是最一般和最靈活的。無論它有多複雜,您都可以將任何表達式的值計算爲String
至debug
。
晶瑩剔透,非常感謝。我想你的徹底解釋彌補了我所期待的並沒有得到的魔法。 :) – teo