天天看點

Java常用的日志架構對比和深入分析

前言

作為一名資深的開發人員,對于日志記錄架構一定不會很陌生。而且幾乎在所有應用裡面,一定會用到各種各樣的 

日志架構用來記錄程式的運作資訊。而對于一個成熟的java應用,這個是必不可少的。在開發和調試階段,日志可以幫助我們更快的定位問題;而在應用的運維過程中,日志系統又可以幫助我們記錄大部分的異常資訊,通常很多企業會通過收集日志資訊來對系統的運作狀态進行實時監控預警。那麼,你對日志架構到底有多了解呢?

常用的日志架構

Log4j

Log4j是apache下一個功能非常豐富的java日志庫實作,Log4j應該是出現比較早而且最受歡迎的java日志組 

件,它是基于java的開源的日志元件。Log4j的功能非常強大,通過Log4j可以把日志輸出到控制台、檔案、使用者界面。也可以輸出到作業系統的事件記錄器和一些系統常駐程序。值得一提的是:Log4j可以允許你非常便捷地自定義日志格式和日志等級,可以幫助開發人員全方位的掌控自己的日志資訊

Log4j2

Log4j2是Log4j1的更新版本。Log4j2基本上把Log4j版本的核心全部重構掉了,而且基于Log4j做了很多優化和改變

Logback

Logback是由Log4j創始人設計的另一個開源日志元件,也是作為Log4j的替代者出現的。而且官方是建議和 

Slf4j一起使用,你們一定不知道Logback、slf4j、Log4j都是出自同一個人吧。 Logback是在Log4j的基礎上做的改進版本,而Slf4j又是同一個人設計的,是以預設就對Slf4j無縫結合。

JDK-Logging

Jdk1.4版本以後開始提供的一個自帶的日志庫實作

統一日志子產品

目前市面上有兩個用得比較廣泛的統一日志規範接口,分别是

SLF4j

SLF4j(Simple Logging Facade For Java)是基于API的java日志架構,SLF4j提供了一個簡單統一的日 

志記錄接口,開發者在配置和部署時,隻需要實作這個接口就可以實作日志功能。可以說,它并不是一個具體的日志解決方案,它隻是服務于各種各樣的日志系統,允許最終使用者在部署應用上使用自己常用的日志系統

Commons-Logging

Common-logging 為衆多具體的日志實作庫提供了一個統一的接口,和SLF4j的作用類似,它允許在運作時綁定任意的日志庫; 

這裡其實有個小故事,當年apache說服Log4j以及其他的日志架構按照Commons-Logging的标準來編寫,但是由于Commons-Logging的類加載有點問題,實作起來不友好。是以Log4j的作者就創作了Slf4j,也是以與Commons-Logging兩份天下

圖說幾個日志架構的關系

各個日志的功能示範

各個日志子產品的功能示範和配置說明,我就不做多說了,網上搜尋下一抓一大把,都講得很詳細。

slf4j和各個日志架構內建的原理

這裡要重點說明一個東西,就是slf4j通過一個非常有趣而且很牛的設計,把各個日志架構去內建進來。 

如果你們去看slf4j的源碼,在LoggerFactory.java裡面有一個這樣的靜态全局變量

private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";

還有一段核心代碼

static Set findPossibleStaticLoggerBinderPathSet() {        LinkedHashSet staticLoggerBinderPathSet = new LinkedHashSet();        try {            ClassLoader ioe = LoggerFactory.class.getClassLoader();            Enumeration paths;            if(ioe == null) {                paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);            } else {                paths = ioe.getResources(STATIC_LOGGER_BINDER_PATH);            }            while(paths.hasMoreElements()) {                URL path = (URL)paths.nextElement();                staticLoggerBinderPathSet.add(path);            }        } catch (IOException var4) {            Util.report("Error getting resources from path", var4);        }        return staticLoggerBinderPathSet;    }

大家對ClassLoader機制了解的同學,這段代碼看起來就非常容易懂了,通過ClassLoader去加載classpath下所有存在StaticLoggerBinder.class的檔案。找到這個檔案以後加到一個集合裡面。通過加載到對應jar中的StaticLoggerBinder。來擷取執行個體。

public static ILoggerFactory getILoggerFactory() {        if (INITIALIZATION_STATE == UNINITIALIZED) {            synchronized (LoggerFactory.class) {                if (INITIALIZATION_STATE == UNINITIALIZED) {                    INITIALIZATION_STATE = ONGOING_INITIALIZATION;                    performInitialization();                }            }        }        switch (INITIALIZATION_STATE) {        case SUCCESSFUL_INITIALIZATION:            return StaticLoggerBinder.getSingleton().getLoggerFactory();        case NOP_FALLBACK_INITIALIZATION:            return NOP_FALLBACK_FACTORY;        case FAILED_INITIALIZATION:            throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);        case ONGOING_INITIALIZATION:            // support re-entrant behavior.            // See also http://jira.qos.ch/browse/SLF4J-97            return SUBST_FACTORY;        }        throw new IllegalStateException("Unreachable code");    }

在這段代碼裡面,可以看到有一個StaticLoggerBinder.getSingleton().getLoggerFactory() 

這個就是在第三方的內建包中傳回的執行個體。這個就是slf4j裡面比較核心的一塊

歡迎工作一到五年的Java程式員朋友們加入Java架構開發:744677563

本群提供免費的學習指導 架構資料 以及免費的解答

不懂得問題都可以在本群提出來 之後還會有職業生涯規劃以及面試指導

進群修改群備注:開發年限-地區-經驗

友善架構師解答問題