Java日志框架slf4j、jcl、jul、log4j1、log4j2、logback大總結

jopen 9年前發布 | 186K 次閱讀 Java日志 日志處理

1 系列目錄

2各種jar包總結

  • log4j1:

    • log4j:log4j1的全部內容
    </li>
  • log4j2:

    • log4j-api:log4j2定義的API
    • log4j-core:log4j2上述API的實現
    • </ul> </li>
    • logback:

      • logback-core:logback的核心包
      • logback-classic:logback實現了slf4j的API
      • </ul> </li>
      • commons-logging:

        • commons-logging:commons-logging的原生全部內容
        • log4j-jcl:commons-logging到log4j2的橋梁
        • jcl-over-slf4j:commons-logging到slf4j的橋梁
        • </ul> </li>
        • slf4j轉向某個實際的日志框架:

          場景介紹:如 使用slf4j的API進行編程,底層想使用log4j1來進行實際的日志輸出,這就是slf4j-log4j12干的事。

          • slf4j-jdk14:slf4j到jdk-logging的橋梁
          • slf4j-log4j12:slf4j到log4j1的橋梁
          • log4j-slf4j-impl:slf4j到log4j2的橋梁
          • logback-classic:slf4j到logback的橋梁
          • slf4j-jcl:slf4j到commons-logging的橋梁
          • </ul> </li>
          • 某個實際的日志框架轉向slf4j:

            場景介紹:如 使用log4j1的API進行編程,但是想最終通過logback來進行輸出,所以就需要先將log4j1的日志輸出轉交給slf4j來輸出,slf4j 再交給logback來輸出。將log4j1的輸出轉給slf4j,這就是log4j-over-slf4j做的事

            這一部分主要用來進行實際的日志框架之間的切換(下文會詳細講解)

            • jul-to-slf4j:jdk-logging到slf4j的橋梁
            • log4j-over-slf4j:log4j1到slf4j的橋梁
            • jcl-over-slf4j:commons-logging到slf4j的橋梁
            • </ul> </li> </ul>

              3集成總結

              3.1 commons-logging與其他日志框架集成

              • 1 commons-logging與jdk-logging集成:

                需要的jar包:

                • commons-logging
                </li>
              • 2 commons-logging與log4j1集成:

                需要的jar包:

                • commons-logging
                • log4j
                • </ul> </li>
                • 3 commons-logging與log4j2集成:

                  需要的jar包:

                  • commons-logging
                  • log4j-api
                  • log4j-core
                  • log4j-jcl(集成包)
                  • </ul> </li>
                  • 4 commons-logging與logback集成:

                    需要的jar包:

                    • logback-core
                    • logback-classic
                    • slf4j-api、jcl-over-slf4j(2個集成包,可以不再需要commons-logging)
                    • </ul> </li>
                    • 5 commons-logging與slf4j集成:

                      需要的jar包:

                      • jcl-over-slf4j(集成包,不再需要commons-logging)
                      • slf4j-api
                      • </ul> </li> </ul>

                        3.2 slf4j與其他日志框架集成

                        • slf4j與jdk-logging集成:

                          需要的jar包:

                          • slf4j-api
                          • slf4j-jdk14(集成包)
                          </li>
                        • slf4j與log4j1集成:

                          需要的jar包:

                          • slf4j-api
                          • log4j
                          • slf4j-log4j12(集成包)
                          • </ul> </li>
                          • slf4j與log4j2集成:

                            需要的jar包:

                            • slf4j-api
                            • log4j-api
                            • log4j-core
                            • log4j-slf4j-impl(集成包)
                            • </ul> </li>
                            • slf4j與logback集成:

                              需要的jar包:

                              • slf4j-api
                              • logback-core
                              • logback-classic(集成包)
                              • </ul> </li>
                              • slf4j與commons-logging集成:

                                需要的jar包:

                                • slf4j-api
                                • commons-logging
                                • slf4j-jcl(集成包)
                                • </ul> </li> </ul>

                                  4 日志系統之間的切換

                                  4.1 log4j無縫切換到logback

                                  4.1.1 案例

                                  我們已經在代碼中使用了log4j1的API來進行日志的輸出,現在想不更改已有代碼的前提下,使之通過logback來進行實際的日志輸出。

                                  已使用的jar包:

                                  • log4j

                                  使用案例:

                                  private static final Logger logger=Logger.getLogger(Log4jTest.class);
                                  
                                  public static void main(String[] args){
                                      if(logger.isInfoEnabled()){
                                          logger.info("log4j info message");
                                      }
                                  }

                                  上述的Logger是log4j1自己的org.apache.log4j.Logger,在上述代碼中,我們在使用log4j1的API進行編程

                                  現在如何能讓上述的日志輸出通過logback來進行輸出呢?

                                  只需要更換一下jar包就可以:

                                  • 第一步:去掉log4j jar包

                                  • 第二步:加入以下jar包

                                    • log4j-over-slf4j(實現log4j1切換到slf4j)
                                    • slf4j-api
                                    • logback-core
                                    • logback-classic
                                  • 第三步:在類路徑下加入logback的配置文件

                                  原理是什么呢?

                                  4.1.2 切換原理

                                  看下log4j-over-slf4j就一目了然了:

                                  Java日志框架slf4j、jcl、jul、log4j1、log4j2、logback大總結

                                  我們可以看到,這里面其實是簡化更改版的log4j。去掉log4j1的原生jar包,換成該簡化更改版的jar包(可以實現無縫遷移)。

                                  但是簡化更改版中的Logger和原生版中的實現就不同了,簡化版中的Logger實現如下(繼承了Category):

                                  public class Category {
                                      private String name;
                                      protected org.slf4j.Logger slf4jLogger;
                                      private org.slf4j.spi.LocationAwareLogger locationAwareLogger;
                                  
                                      Category(String name) {
                                          this.name = name;
                                          slf4jLogger = LoggerFactory.getLogger(name);
                                          if (slf4jLogger instanceof LocationAwareLogger) {
                                              locationAwareLogger = (LocationAwareLogger) slf4jLogger;
                                          }
                                      }
                                  }

                                  從上面可以看到簡化版中的Logger內部是使用slf4j的API來生成的,所以我們使用的簡化版的Logger會委托給slf4j來進行輸出, 由于當前類路徑下有logback-classic,所以slf4j會選擇logback進行輸出。從而實現了log4j到logback的日志切換。

                                  下面的內容就只講解日志系統到slf4j的切換,不再講解slf4j選擇何種日志來輸出

                                  4.2 jdk-logging無縫切換到logback

                                  4.2.1 案例

                                  private static final Logger logger=Logger.getLogger(JulSlf4jLog4jTest.class.getName());
                                  
                                  public static void main(String[] args){
                                      logger.log(Level.INFO,"jul info a msg");
                                      logger.log(Level.WARNING,"jul waring a msg");
                                  }

                                  可以看到上述是使用jdk-logging自帶的API來進行編程的,現在我們想這些日志交給logback來輸出

                                  解決辦法如下:

                                  • 第一步:加入以下jar包:

                                    • jul-to-slf4j (實現jdk-logging切換到slf4j)
                                    • slf4j-api
                                    • logback-core
                                    • logback-classic
                                  • 第二步:在類路徑下加入logback的配置文件

                                  • 第三步:在代碼中加入如下代碼:

                                    static{
                                        SLF4JBridgeHandler.install();
                                    }

                                  4.2.2 切換原理

                                  先來看下jul-to-slf4j jar包中的內容:

                                  Java日志框架slf4j、jcl、jul、log4j1、log4j2、logback大總結

                                  我們看到只有一個類:SLF4JBridgeHandler

                                  它繼承了jdk-logging中定義的java.util.logging.Handler,Handler是jdk-logging處理日志過 程中的一個處理器(具體我也沒仔細研究過),在使用之前,必須要提前注冊這個處理器,即上述的SLF4JBridgeHandler.install() 操作,install后我們就可以通過這個handler實現日志的切換工作,如下:

                                  protected Logger getSLF4JLogger(LogRecord record) {
                                      String name = record.getLoggerName();
                                      if (name == null) {
                                          name = UNKNOWN_LOGGER_NAME;
                                      }
                                      return LoggerFactory.getLogger(name);
                                  }

                                  在處理日志的過程中,使用了slf4j的原生方式LoggerFactory來獲取一個slf4j定義的Logger來進行日志的輸出

                                  而slf4j則又會選擇logback來進行實際的日志輸出

                                  4.3 commons-logging切換到logback

                                  4.3.1 使用案例

                                  使用的jar包

                                  • commons-logging

                                  案例如下:

                                  private static Log logger=LogFactory.getLog(JulJclTest.class);
                                  
                                  public static void main(String[] args){
                                      if(logger.isTraceEnabled()){
                                          logger.trace("commons-logging-jcl trace message");
                                      }
                                  }

                                  可以看到我們使用commons-logging的API來進行日志的編程操作,現在想切換成logback來進行日志的輸出(這其實就是commons-logging與logback的集成)

                                  解決辦法如下:

                                  • 第一步:去掉commons-logging jar包(其實去不去都無所謂)

                                  • 第二步:加入以下jar包:

                                    • jcl-over-slf4j(實現commons-logging切換到slf4j)
                                    • slf4j-api
                                    • logback-core
                                    • logback-classic
                                  • 第三步:在類路徑下加入logback的配置文件

                                  4.3.2 切換原理

                                  這個原理之前都已經說過了,可以看下commons-logging與logback的集成

                                  就是commons-logging通過jcl-over-slf4j 來選擇slf4j作為底層的日志輸出對象,而slf4j又選擇logback來作為底層的日志輸出對象。

                                  4.4 常用的日志場景切換解釋

                                  上面把日志的切換原理說清楚了,下面就針對具體的例子來進行應用

                                  先來看下slf4j官方的一張圖:

                                  Java日志框架slf4j、jcl、jul、log4j1、log4j2、logback大總結

                                  下面分別詳細說明這三個案例

                                  4.4.1 左上圖

                                  • 現狀:

                                    目前的應用程序中已經使用了如下混雜方式的API來進行日志的編程:

                                    • commons-logging
                                    • log4j1
                                    • jdk-logging

                                    現在想統一將日志的輸出交給logback

                                  • 解決辦法:

                                    • 第一步:將上述日志系統全部無縫先切換到slf4j

                                      • 去掉commons-logging(其實去不去都可以),使用jcl-over-slf4j將commons-logging的底層日志輸出切換到slf4j
                                      • 去掉log4j1(必須去掉),使用log4j-over-slf4j,將log4j1的日志輸出切換到slf4j
                                      • 使用jul-to-slf4j,將jul的日志輸出切換到slf4j
                                    • 第二步:使slf4j選擇logback來作為底層日志輸出

                                    加入以下jar包:

                                    • slf4j-api
                                    • logback-core
                                    • logback-classic

                                  下面的2張圖和上面就很類似

                                  4.4.2 右上圖

                                  • 現狀:

                                    目前的應用程序中已經使用了如下混雜方式的API來進行日志的編程:

                                    • commons-logging
                                    • jdk-logging

                                    現在想統一將日志的輸出交給log4j1

                                  • 解決辦法:

                                    • 第一步:將上述日志系統全部無縫先切換到slf4j

                                      • 去掉commons-logging(其實去不去都可以),使用jcl-over-slf4j將commons-logging的底層日志輸出切換到slf4j
                                      • 使用jul-to-slf4j,將jul的日志輸出切換到slf4j
                                    • 第二步:使slf4j選擇log4j1來作為底層日志輸出

                                    加入以下jar包:

                                    • slf4j-api
                                    • log4j
                                    • slf4j-log4j12(集成包)

                                  4.4.3 左下圖

                                  • 現狀:

                                    目前的應用程序中已經使用了如下混雜方式的API來進行日志的編程:

                                    • commons-logging
                                    • log4j

                                    現在想統一將日志的輸出交給jdk-logging

                                  • 解決辦法:

                                    • 第一步:將上述日志系統全部無縫先切換到slf4j

                                      • 去掉commons-logging(其實去不去都可以),使用jcl-over-slf4j將commons-logging的底層日志輸出切換到slf4j
                                      • 去掉log4j1(必須去掉),使用log4j-over-slf4j,將log4j1的日志輸出切換到slf4j
                                    • 第二步:使slf4j選擇jdk-logging來作為底層日志輸出

                                    加入以下jar包:

                                    • slf4j-api
                                    • slf4j-jdk14(集成包)

                                  5 沖突說明

                                  仍然是這里的內容slf4j官網的沖突說明

                                  其實明白上面介紹的各jar包的作用,就很容易理解

                                  5.1 jcl-over-slf4j 與 slf4j-jcl 沖突

                                  • jcl-over-slf4j: commons-logging切換到slf4j

                                  • slf4j-jcl : slf4j切換到commons-logging

                                  如果這兩者共存的話,必然造成相互委托,造成內存溢出

                                  5.2 log4j-over-slf4j 與 slf4j-log4j12 沖突

                                  • log4j-over-slf4j : log4j1切換到slf4j
                                  • slf4j-log4j12 : slf4j切換到log4j1

                                  如果這兩者共存的話,必然造成相互委托,造成內存溢出。但是log4j-over-slf4內部做了一個判斷,可以防止造成內存溢出:

                                  即判斷slf4j-log4j12 jar包中的org.slf4j.impl.Log4jLoggerFactory是否存在,如果存在則表示沖突了,拋出異常提示用戶要去掉對應的jar 包,代碼如下,在slf4j-log4j12 jar包的org.apache.log4j.Log4jLoggerFactory中:

                                  Java日志框架slf4j、jcl、jul、log4j1、log4j2、logback大總結

                                  5.3 jul-to-slf4j 與 slf4j-jdk14 沖突

                                  • jul-to-slf4j : jdk-logging切換到slf4j
                                  • slf4j-jdk14 : slf4j切換到jdk-logging

                                  如果這兩者共存的話,必然造成相互委托,造成內存溢出

                                  6 結束語

                                  至此,這個日志系列就算終于完成了。它注重于日志系統之間的交互與集成,所以想深入研究單個日志系統的架構的話,就需要各位自行去深入研究了。

                                  來自:http://my.oschina.net/pingpangkuangmo/blog/410224

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!