LogBack是一個日誌框架,它與Log4j能夠說是同出一源,都出自Ceki Gülcü之手。(log4j的原型是早前由Ceki Gülcü貢獻給Apache基金會的)html
Slf4j是The Simple Logging Facade for Java的簡稱,是一個簡單日誌門面抽象框架,它自己只提供了日誌Facade API和一個簡單的日誌類實現,通常常配合Log4j,LogBack,java.util.logging使用。Slf4j做爲應用層的Log接入時,程序能夠根據實際應用場景動態調整底層的日誌實現框架(Log4j/LogBack/JdkLog...);java
LogBack和Log4j都是開源日記工具庫,LogBack是Log4j的改良版本,比Log4j擁有更多的特性,同時也帶來很大性能提高。詳細數據可參照下面地址:Reasons to prefer logback over log4japi
LogBack官方建議配合Slf4j使用,這樣能夠靈活地替換底層日誌框架。app
(note: 爲了優化log4j,以及更大性能的提高,Apache基金會已經着手開發了log4j 2.0, 其中也借鑑和吸取了logback的一些先進特性,目前log4j2還處於beta階段)框架
LogBack被分爲3個組件,logback-core, logback-classic 和 logback-access.eclipse
其中logback-core提供了LogBack的核心功能,是另外兩個組件的基礎。工具
logback-classic則實現了Slf4j的API,因此當想配合Slf4j使用時,須要將logback-classic加入classpath.性能
logback-access是爲了集成Servlet環境而準備的,可提供HTTP-access的日誌接口;優化
如今經常使用的是將slf4j+Logback進行配套使用,因此須要將slf4j-api.jar, logback-core.jar, log-classic.jar加入classpath.lua
以後編寫logback.xml配置文件,一樣該文件要加入classpath中,這樣LogBack啓動的時候會自動掃描到並加載。
(note: 若LogBack沒法檢索到相關的配置文件,則會啓用默認配置,將日誌按照默認格式輸出於控制檯)
LogBack的配置大概包括3部分,Appender,Logger,Root的配置。
下面經過一個配置文件的示例來快速瞭解logback的配置:
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true" scan="true" scanPeriod="30 seconds"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are by default assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - %m%n</pattern> <!-- 經常使用的Pattern變量,你們可打開該pattern進行輸出觀察 --> <!-- <pattern> %d{yyyy-MM-dd HH:mm:ss} [%level] - %msg%n Logger: %logger Class: %class File: %file Caller: %caller Line: %line Message: %m Method: %M Relative: %relative Thread: %thread Exception: %ex xException: %xEx nopException: %nopex rException: %rEx Marker: %marker %n </pattern> --> </encoder> </appender> <!-- 按日期區分的滾動日誌 --> <appender name="ERROR-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/error.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- daily rollover --> <fileNamePattern>error.%d{yyyy-MM-dd}.log.zip</fileNamePattern> <!-- keep 30 days' worth of history --> <maxHistory>30</maxHistory> </rollingPolicy> </appender> <!-- 按文件大小區分的滾動日誌 --> <appender name="INFO-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/info.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>info.%i.log</fileNamePattern> <minIndex>1</minIndex> <maxIndex>3</maxIndex> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>5MB</maxFileSize> </triggeringPolicy> </appender> <!-- 按日期和大小區分的滾動日誌 --> <appender name="DEBUG-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/debug.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!-- or whenever the file size reaches 100MB --> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!-- 級別閥值過濾 --> <appender name="SUM-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/sum.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern> </encoder> <!-- deny all events with a level below INFO, that is TRACE and DEBUG --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!-- or whenever the file size reaches 100MB --> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <root level="debug"> <appender-ref ref="STDOUT" /> <appender-ref ref="ERROR-OUT" /> <appender-ref ref="INFO-OUT" /> <appender-ref ref="DEBUG-OUT" /> <appender-ref ref="SUM-OUT" /> </root> </configuration>
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true" scan="false" scanPeriod="30 seconds"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are by default assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - %m%n</pattern> </encoder> </appender> <!-- 按日期區分的滾動日誌 --> <appender name="APP" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/app.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern> </encoder> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- daily rollover --> <fileNamePattern>app.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- keep 30 days' worth of history --> <maxHistory>30</maxHistory> </rollingPolicy> </appender> <!-- 按日期和大小區分的滾動日誌 --> <appender name="DEBUG-OUT" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/debug.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%class:%line] - %m%n</pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!-- or whenever the file size reaches 100MB --> <maxFileSize>30MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <root level="debug"> <appender-ref ref="STDOUT" /> <appender-ref ref="APP" /> <appender-ref ref="DEBUG-OUT" /> </root> </configuration>
public class Slf4jTest { private static Logger Log = LoggerFactory.getLogger(Slf4jTest.class); @Test public void testLogBack(){ Log.debug("Test the MessageFormat for {} to {} endTo {}", 1,2,3); Log.info("Test the MessageFormat for {} to {} endTo {}", 1,2,3); Log.error("Test the MessageFormat for {} to {} endTo {}", 1,2,3); try{ throw new IllegalStateException("try to throw an Exception"); }catch(Exception e){ Log.error(e.getMessage(),e); } } }
2013-12-30 21:37:18 [DEBUG] - Test the MessageFormat for 1 to 2 endTo 3 2013-12-30 21:37:18 [INFO] - Test the MessageFormat for 1 to 2 endTo 3 2013-12-30 21:37:18 [ERROR] - Test the MessageFormat for 1 to 2 endTo 3 2013-12-30 21:37:18 [ERROR] - try to throw an Exception java.lang.IllegalStateException: try to throw an Exception at logs.Slf4jTest.testLogBack(Slf4jTest.java:19) ~[bin/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_18] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_18] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_18] at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_18] at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) [junit.jar:na] at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit.jar:na] at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) [junit.jar:na] at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit.jar:na] at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) [junit.jar:na] at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) [junit.jar:na] at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) [junit.jar:na] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) [junit.jar:na] at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) [junit.jar:na] at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) [junit.jar:na] at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) [junit.jar:na] at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) [junit.jar:na] at org.junit.runners.ParentRunner.run(ParentRunner.java:309) [junit.jar:na] at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) [.cp/:na]