Java日志相關記錄 (Jul jcl log4j log4j2 Logback SLF4J)

jopen 10年前發布 | 24K 次閱讀 日志處理

一、寫在前面

在java 中實現記錄日志的方式有很多種
1. 最初的方式,就是system.print.out ,err 這樣直接在控制臺打印消息,缺點太多了,這樣與業務邏輯無關的代碼會變得更多,不能按日志等及輸出,以及那些不輸出等。
2. JUL,java util logging在jdk的java.util.logging包中,也叫jkdLog或者jdk14log; 在JDK 1.4 版本之后,java提供了日志的API ,可以往文件中寫日志了,最方便不需要第三方包,其實際使用人較少。
3. log4j , 最強大的記錄日志的方式。 可以通過配置 .properties 或是 .xml 的文件, 配置日志的目的地,格式等等,基于老的jdk性能不高,該項目現在已經停止維護,但是用的人還是最多的。
4. Log4j2 該項目是log4j的升級版,性能較好,也吸收了logback等日志記錄組件的優點。
5. commons-logging是一個日志接口,最綜合和常見的日志記錄方式, 經常是和log4j或者log4j2 結合起來使用。
6. Slf4j也是一個日志接口,最常見的是和logback一起使用。
7. 日志等級其實最常用的就是這四個等級(debug,info,warn,error)。

二、JUL(java util logger)

使用java 自帶的logger最方便的作用提無需引入第三方包
直接上代碼:

package com.xxx.test;
import java.io.IOException;
import java.util.Date;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

public class TestLogJava {
    public static void main(String[] args) throws IOException{
        Logger log = Logger.getLogger("tesglog");
        log.setLevel(Level.ALL);
        FileHandler fileHandler = new FileHandler("testlog.log");
        fileHandler.setLevel(Level.ALL);
        fileHandler.setFormatter(new LogFormatter());
        log.addHandler(fileHandler);
        log.info("This is test java util log"); 
        log.warning("warning .........");
        log.log(Level.FINE, "fine...");
        log.finer("finer ....");
    }
}

class LogFormatter extends Formatter {
    @Override
    public String format(LogRecord record) {
        Date date = new Date();
        String sDate = date.toString();
        return "[" + sDate + "]" + "[" + record.getLevel() + "]"
                + record.getClass() + record.getMessage() + "\n";
    }
}



Java util logger使用的日志級別:SEVERE(最高值),WARNING,INFO,CONFIG,FINE,FINER,FINEST(最低值)以及OFF和ALL
先通地Logger工廠獲得一個log實例,日志記當格是默認是xml 使用前最好先自己格式化自己所要的格式(上面的LogFormatter就是自定義格式)。log的Handler有許多可以使用常見是寫到文件也就是FileHandler。
使用步驟:new 一個FileHandler 實例,設定fileHandler的等級和格式,并添加到log實例上,然后就是直接使用log.info()寫入了。

三、JCL(Jakarta commons logger)

說的是java 通用日志,其實是apache出品的通用日志接口,是一個接口。
提供的是一個日志(Log)接口(interface),同時兼顧輕量級和不依賴于具體的日志實現工具。它提供給中間件/日志工具開發者一個簡單的日志操作抽象,允許程序開發人員使用不同的具體日志實現工具。
JCL有兩個基本的抽象類:Log(基本記錄器)和LogFactory(負責創建Log實例)。當commons-logging.jar被加入到 CLASSPATH之后,它會合理地猜測你想用的日志工具,然后進行自我設置,用戶根本不需要做任何設置。默認的LogFactory是按照下列的步驟去發現并決定那個日志工具將被使用的(按照順序,尋找過程會在找到第一個工具時中止):
   1. 尋找當前factory中名叫org.apache.commons.logging.Log配置屬性的值
   2. 尋找系統中屬性中名叫org.apache.commons.logging.Log的值
   3. 如果應用程序的classpath中有log4j,則使用相關的包裝(wrapper)類(Log4JLogger)
   4. 如果應用程序運行在jdk1.4的系統中,使用相關的包裝類(Jdk14Logger)
   5. 使用簡易日志包裝類(SimpleLog)
org.apache.commons.logging.Log的具體實現有如下:
-org.apache.commons.logging.impl.Jdk14Logger 使用JDK1.4。
-org.apache.commons.logging.impl.Log4JLogger 使用Log4J。
-org.apache.commons.logging.impl.LogKitLogger 使用 avalon-Logkit。
-org.apache.commons.logging.impl.SimpleLog common-logging自帶日志實現類。它實現了Log接口,把日志消息都輸出到系統錯誤流System.err 中。 
-org.apache.commons.logging.impl.NoOpLog common-logging自帶日志實現類。它實現了Log接口。 其輸出日志的方法中不進行任何操作。

package com.xxx.test;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.*;
public class TestCommonLog {
    private static Log log = LogFactory.getLog(TestCommonLog.class);
    public static void main(String[] args) {
        log.debug("debug ......");
        log.info("info ......");
        log.warn("warn ......");
        log.error("error ......");
        log.fatal("fatal ......");
    }
}


四、log4j(log4j版本1)

Log4j是java開發用得最多最常見的日志組件,這個是組件,是有完整的實現。可以完整的獨立使用。
直接上代碼:

Log4j.properties

### \u8BBE\u7F6E###
log4j.rootLogger = debug,stdout,D,E

### \u8F93\u51FA\u4FE1\u606F\u5230\u63A7\u5236\u62AC ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### \u8F93\u51FADEBUG \u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7\u5230=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### \u8F93\u51FAERROR \u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7\u5230=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n



Log4jTest.java

package com.xxx.test;
import org.apache.log4j.Logger;
public class Log4jTest {
    private static Logger logger = Logger.getLogger(Log4jTest.class);
    public static void main(String args[]) {
        // 記錄debug級別的信息
        logger.debug("debug");
        // 記錄info級別的信息
        logger.info("info");
        // 記錄error級別的信息
        logger.error("error");
    }
}



五、log4j2使用

Log4j2是log4j的重構升級版,他改進了log4j性能和不足,吸取了logback優點
不說了直接上代碼:

Log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%m%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Root level="DEBUG">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>


Log4j2Test.java

package com.xxx.test;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
public class Log4j2Test {
    private static Logger logger = LogManager.getLogger(Log4j2Test.class);
    public static boolean hello() {
        logger.entry();   //trace級別的信息,單獨列出來是希望你在某個方法或者程序邏輯開始的時候調用,和logger.trace("entry")基本一個意思
        logger.error("Did it again!");   //error級別的信息,參數就是你輸出的信息
        logger.info("我是info信息");    //info級別的信息
        logger.debug("我是debug信息");
        logger.warn("我是warn信息");
        logger.fatal("我是fatal信息");
        logger.log(Level.DEBUG, "我是debug信息");   //這個就是制定Level類型的調用:誰閑著沒事調用這個,也不一定哦!
        logger.exit();    //和entry()對應的結束方法,和logger.trace("exit");一個意思
        return false;
    }
    public static void main(String[] args) {
        hello();
    }
}

log4j2在沒有任何配置的情況下文件時會自動使用默認的配置:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Root level="error">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>


該配置只有一個Appender:Console,目標是SYSTEM_OUT,即日志內容,都會打印在eclipse控制臺上。Root Logger的級別是error,即:所有error及以上級別的日志才會記錄。(注:日志級別順序為 TRACE < DEBUG < INFO < WARN < ERROR < FATAL ),所以最終只有2日志會輸出(error,fatal)


再來Log4j2的詳細一點的配置

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="OFF">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>

        <File name="ERROR" fileName="logs/error.log">
            <ThresholdFilter level="error" onMatch="ACCEPT"
                onMismatch="DENY" />
            <PatternLayout
                pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n" />
        </File>

        <RollingFile name="RollingFile" fileName="logs/app.log"
            filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout
                pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n" />
            <SizeBasedTriggeringPolicy size="50MB" />
        </RollingFile>

        <RollingFile name="ROLLING" fileName="d:/logs/howsun.log"
            filePattern="d:/logs/howsun_%d{yyyy-MM-dd}_%i.log">
            <PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
            <Policies>
                <TimeBasedTriggeringPolicy modulate="true"
                    interval="24" />
                <SizeBasedTriggeringPolicy size="51200 KB" />
            </Policies>
            <DefaultRolloverStrategy max="20" />
        </RollingFile>

        <properties>
            <property name="filenameLog">logs/payPlatform.log</property>
        </properties>

        <!-- 定義后臺文檔日志記錄 -->
        <RollingFile name="RollingFile" fileName="${filenameLog}"
            filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout>
                <Pattern>%d{yyyy-MM-dd HH:mm:ss} [%p] [%t] %c{1}.%M(%L) | %m%n
                </Pattern>
            </PatternLayout>
            <Policies>
                <!-- 定義log文件封存的周期 -->
                <TimeBasedTriggeringPolicy interval="1"
                    modulate="true" />
                <SizeBasedTriggeringPolicy size="100 MB" />
            </Policies>
            <DefaultRolloverStrategy fileIndex="max" max="2" />
        </RollingFile>

    </Appenders>
    <Loggers>
        <Root level="DEBUG">
            <AppenderRef ref="Console" />
            <appender-ref ref="ROLLING" />
            <appenderRef ref="RollingFile" />
        </Root>
    </Loggers>
</Configuration>



六、SLF4J與Logback 

SLF4J全名Simple Logging Facade for Java
不是具體的日志解決方案,它只服務于各種各樣的日志系統。按照官方的說法,SLF4J是一個用于日志系統的簡單Facade,允許最終用戶在部署其應用時使用其所希望的日志系統。
SLF4J同apache的commons-logger一樣,都是供示一個簡單的接口,不是一個完格的日志解決方案他一般需要和其它日志系統進行配合使用。
SLF4J創建項目在包中引入SLF4J的核心接口slf4j-api.jar包
上代碼:

package com.xxx.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogbackTest {
    private static Logger logger = LoggerFactory.getLogger(LogbackTest.class);
    public static void main(String[] args) {
        System.out.println("-----");
        logger.trace("trace");  
        logger.debug("debug");  
        logger.info("info");  
        logger.warn("warn");  
        logger.error("error");
    }
}



如果沒有引入其它包,是打印不出日志的,


這里必須在再引入一個現實的包可以使用slf4j-simple.jar,這樣slf4j-api會調用slf4j-simple.jarsimple現實(全部打印在console上),也可以使用slf4j-nop.jar就是無任何操作的實現。
同理,也可以在jdk1.4上使用slf4j-jdk14.jar包來使用jdk14logger的實現,也可使用slf4j-jcl.jarJakarta commons logger的實現,雖然他自身也是一個通用日志接口),同樣可以使用slf4j-logj12.jar的實現了。只是在使用其它實現是需要加入其它相應日志系統的jar 包并同時做好相應日志系統的配置,例使用了slf4j-log4j12.jar則還需要加入log4j-1.2.7.jar 包,并且在寫好相應的log4j.properties配置文件。

SLF4J這種機制還可以把原來用的不是slf4j這種日志接口的直接轉換成slf4j。例原來使用的是commons-logging可以把原來的commons-logging.jar包刪除,把jcl-over-slf4j.jar添加到項目即可。

提到slf4j就不得不提一下logback

Logback同也是由log4j主創人創立,slf4j也是他搞的。改寫了log4j的核心提高了性能,意在替換log4j(指log4j-v1)。logback項目主要有三個部分core, classic, access, corelogback的核心,classicslf4japi的實現,而access則是配使servlet容器配合提供http訪問記錄。

使用同上,需要加入slf4j-api.jarlogback-core.jar,logback-classic.jar,logback-access.jar

Slf4jLogbackTest.java

package com.xxx.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogbackTest {
    private static Logger logger = LoggerFactory.getLogger(LogbackTest.class);
    public static void main(String[] args) {    
     logger.trace("======trace");  
        logger.debug("======debug");  
        logger.info("======info");  
        logger.warn("======warn");  
        logger.error("======error");
    }
}



Logback.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="true">
  <appender name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned by default the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>
  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>



這個是logback的配置文件,其實不配logback.xml也是可以的,程序會自動加載一個默認BasicConfigurator的配置,最 小化 配置 由 一個 關聯 到 根 logger ConsoleAppender 組成。 輸出用模式為%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}- %msg%n 的 PatternLayoutEncoder 進行格式化,根 logger 默認級別是 DEBUG
說到這里也說一下logback讀取配置文件規則:,先讀取logback-test.xml,沒有則查找logback.xml如果也沒有就加載BasicConfigurator配置。

寫在最后:

jdkLog就是JUL,在項目實際中用得較少,小的項目中都是直接使用log4j或者log4j2,或都使用commons-logging再配合log4j或者log4j2。也有許多項目直接使用slf4j+logback
一般建議是使用commons-logging+log4j或者slf4j+logback吧,如果項目的其它組件充許要不直接上log4j2也是可以的。


來自: http://my.oschina.net/lenglingx/blog/546961

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