Logback是由log4j創始人設計的又一個開源日誌組件。logback當前分紅三個模塊:logback-core,logback-classic和logback-access。logback-core是其它兩個模塊的基礎模塊。logback-classic是log4j的一個改良版本。此外logback-classic完整實現SLF4J API使你能夠很方便地更換成其它日誌系統如log4j或JDK14 Logging。logback-access訪問模塊與Servlet容器集成提供經過Http來訪問日誌的功能。html
logback的核心,logback-core
包java
logback建議使用slf4j來管理日誌,方便替換底層實現,要用slf4j,就在依賴中加入logback-classic
包和slf4j-api
包。mysql
加入junit
測試。sql
pom.xml:數據庫
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.fengyuan</groupId> <artifactId>logback-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
在項目classpath下加入logback.xml
:apache
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true" scan="true" scanPeriod="30 seconds"> <!-- 輸出到控制檯 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] - %m%n</pattern> </encoder> </appender> <!-- error日誌 --> <!-- 按日期滾動日誌 --> <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"> <fileNamePattern>error.%d{yyyy-MM-dd}.log.zip</fileNamePattern> <!-- 保存30天曆史 --> <maxHistory>30</maxHistory> </rollingPolicy> </appender> <!-- info日誌 --> <!-- 按文件大小滾動日誌 --> <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> <!-- debug日誌 --> <!-- 按日期和大小滾動日誌 --> <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"> <fileNamePattern>debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!-- 配置好前面對應的appender --> <root level="debug"> <appender-ref ref="STDOUT" /> <appender-ref ref="ERROR-OUT" /> <appender-ref ref="INFO-OUT" /> <appender-ref ref="DEBUG-OUT" /> </root> </configuration>
包括日誌文件的路徑,保存的時間,已經滾動的策略都在配置文件中配置,具體看註釋。配置文件是從櫺楓的這篇博客裏學習的,感謝。api
測試類:app
package com.fengyuan.client; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Main { private static Logger log = LoggerFactory.getLogger(Main.class); @Test public void testLogBack() { log.debug("I am debug"); log.info("I am info"); log.error("I am error"); try { throw new IllegalStateException("I am exception"); } catch (Exception e) { log.error(e.getMessage(), e); } } }
執行結果:eclipse
控制檯輸出:maven
10:35:19,739 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy] 10:35:19,739 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml] 10:35:19,739 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [file:/D:/scm-workspace/logback-demo/target/classes/logback.xml] 10:35:19,803 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Setting ReconfigureOnChangeFilter scanning period to 30 seconds 10:35:19,803 |-INFO in ReconfigureOnChangeFilter{invocationCounter=0} - Will scan for changes in [[D:\scm-workspace\logback-demo\target\classes\logback.xml]] every 30 seconds. 10:35:19,803 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Adding ReconfigureOnChangeFilter as a turbo filter 10:35:19,810 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender] 10:35:19,812 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT] 10:35:19,826 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 10:35:19,848 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.rolling.RollingFileAppender] 10:35:19,850 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [ERROR-OUT] 10:35:19,854 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 10:35:19,866 |-INFO in c.q.l.core.rolling.TimeBasedRollingPolicy - Will use zip compression 10:35:19,868 |-INFO in c.q.l.core.rolling.TimeBasedRollingPolicy - Will use the pattern error.%d{yyyy-MM-dd}.log for the active file 10:35:19,875 |-INFO in c.q.l.core.rolling.DefaultTimeBasedFileNamingAndTriggeringPolicy - The date pattern is 'yyyy-MM-dd' from file name pattern 'error.%d{yyyy-MM-dd}.log.zip'. 10:35:19,875 |-INFO in c.q.l.core.rolling.DefaultTimeBasedFileNamingAndTriggeringPolicy - Roll-over at midnight. 10:35:19,877 |-INFO in c.q.l.core.rolling.DefaultTimeBasedFileNamingAndTriggeringPolicy - Setting initial period to Fri Aug 26 10:35:19 CST 2016 10:35:19,879 |-INFO in ch.qos.logback.core.rolling.RollingFileAppender[ERROR-OUT] - Active log file name: logs/error.log 10:35:19,879 |-INFO in ch.qos.logback.core.rolling.RollingFileAppender[ERROR-OUT] - File property is set to [logs/error.log] 10:35:19,880 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.rolling.RollingFileAppender] 10:35:19,880 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [INFO-OUT] 10:35:19,881 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 10:35:19,884 |-INFO in ch.qos.logback.core.rolling.FixedWindowRollingPolicy@234bef66 - No compression will be used 10:35:19,887 |-INFO in ch.qos.logback.core.rolling.RollingFileAppender[INFO-OUT] - Active log file name: logs/info.log 10:35:19,887 |-INFO in ch.qos.logback.core.rolling.RollingFileAppender[INFO-OUT] - File property is set to [logs/info.log] 10:35:19,887 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.rolling.RollingFileAppender] 10:35:19,887 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [DEBUG-OUT] 10:35:19,888 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property 10:35:19,893 |-INFO in c.q.l.core.rolling.TimeBasedRollingPolicy - No compression will be used 10:35:19,893 |-INFO in c.q.l.core.rolling.TimeBasedRollingPolicy - Will use the pattern debug-%d{yyyy-MM-dd}.%i.log for the active file 10:35:19,894 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@39fb3ab6 - The date pattern is 'yyyy-MM-dd' from file name pattern 'debug-%d{yyyy-MM-dd}.%i.log'. 10:35:19,894 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@39fb3ab6 - Roll-over at midnight. 10:35:19,894 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@39fb3ab6 - Setting initial period to Fri Aug 26 10:35:19 CST 2016 10:35:19,895 |-INFO in ch.qos.logback.core.rolling.RollingFileAppender[DEBUG-OUT] - Active log file name: logs/debug.log 10:35:19,895 |-INFO in ch.qos.logback.core.rolling.RollingFileAppender[DEBUG-OUT] - File property is set to [logs/debug.log] 10:35:19,895 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.classic.db.DBAppender] 10:35:19,899 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [DB] 10:35:20,088 |-INFO in ch.qos.logback.core.db.DriverManagerConnectionSource@63753b6d - Driver name=MySQL Connector Java 10:35:20,088 |-INFO in ch.qos.logback.core.db.DriverManagerConnectionSource@63753b6d - Driver version=mysql-connector-java-5.1.38 ( Revision: fe541c166cec739c74cc727c5da96c1028b4834a ) 10:35:20,088 |-INFO in ch.qos.logback.core.db.DriverManagerConnectionSource@63753b6d - supportsGetGeneratedKeys=true 10:35:20,090 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to DEBUG 10:35:20,091 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT] 10:35:20,091 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [ERROR-OUT] to Logger[ROOT] 10:35:20,091 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [INFO-OUT] to Logger[ROOT] 10:35:20,091 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [DEBUG-OUT] to Logger[ROOT] 10:35:20,091 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration. 10:35:20,092 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@731a74c - Registering current configuration as safe fallback point 2016-08-26 10:35:20 [DEBUG] - I am debug 2016-08-26 10:35:20 [INFO] - I am info 2016-08-26 10:35:20 [ERROR] - I am error 2016-08-26 10:35:20 [ERROR] - I am exception java.lang.IllegalStateException: I am exception at com.fengyuan.client.Main.testLogBack(Main.java:19) ~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_65] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_65] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_65] at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_65] at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) [junit-4.12.jar:4.12] at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12] at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) [junit-4.12.jar:4.12] at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) [junit-4.12.jar:4.12] at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) [junit-4.12.jar:4.12] at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12] at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) [.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:459) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na]
在項目路徑下多了一個logs文件夾,裏面有3個文件,每一個文件記錄對應的日誌:
能夠藉助Lombok來簡化代碼的編寫。
有了Lombok,只須要在要寫日誌的類中加入@Slf4j等註解,不用再寫private static Logger log = LoggerFactory.getLogger(Main.class);
使用Lombok後的測試類:
package com.fengyuan.client; import org.junit.Test; import lombok.extern.slf4j.Slf4j; @Slf4j public class Main { @Test public void testLogBack() { log.debug("I am debug"); log.info("I am info"); log.error("I am error"); try { throw new IllegalStateException("I am exception"); } catch (Exception e) { log.error(e.getMessage(), e); } } }
首先在數據庫中建三張表,用來存儲日誌記錄:
BEGIN; DROP TABLE IF EXISTS logging_event_property; DROP TABLE IF EXISTS logging_event_exception; DROP TABLE IF EXISTS logging_event; COMMIT; BEGIN; CREATE TABLE logging_event( timestmp BIGINT NOT NULL, formatted_message TEXT NOT NULL, logger_name VARCHAR(254) NOT NULL, level_string VARCHAR(254) NOT NULL, thread_name VARCHAR(254), reference_flag SMALLINT, arg0 VARCHAR(254), arg1 VARCHAR(254), arg2 VARCHAR(254), arg3 VARCHAR(254), caller_filename VARCHAR(254) NOT NULL, caller_class VARCHAR(254) NOT NULL, caller_method VARCHAR(254) NOT NULL, caller_line CHAR(4) NOT NULL, event_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY ); COMMIT; BEGIN; CREATE TABLE logging_event_property( event_id BIGINT NOT NULL, mapped_key VARCHAR(254) NOT NULL, mapped_value TEXT, PRIMARY KEY(event_id, mapped_key), FOREIGN KEY (event_id) REFERENCES logging_event(event_id) ); COMMIT; BEGIN; CREATE TABLE logging_event_exception ( event_id BIGINT NOT NULL, i SMALLINT NOT NULL, trace_line VARCHAR(254) NOT NULL, PRIMARY KEY(event_id, i), FOREIGN KEY (event_id) REFERENCES logging_event(event_id) ); COMMIT;
在logback.xml
中加入輸出到數據庫的appender,配置好數據源:
<!-- 輸出到數據庫 --> <appender name="DB" class="ch.qos.logback.classic.db.DBAppender"> <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"> <driverClass>com.mysql.jdbc.Driver</driverClass> <url>jdbc:mysql://localhost:3306/test</url> <user>root</user> <password>123456</password> </connectionSource> </appender>
加入引用
<appender-ref ref="DB" />
這一步不少人容易忘記,配置好相應的配置以後,要記得加入mysql驅動的依賴:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency>
而後,日誌就會輸出到數據表中了。