在項目開發(fā)中,為了跟蹤代碼的運行情況,常常要使用日志來記錄信息。在 Java 世界,有很多的日志工具庫來實現(xiàn)日志功能,避免了我們重復(fù)造輪子。我們先來逐一了解一下主流日志工具。
日志框架
java.util.logging (JUL)
JDK1.4 開始,通過?java.util.logging?提供日志功能。
它能滿足基本的日志需要,但是功能沒有 Log4j 強大,而且使用范圍也沒有 Log4j 廣泛。
Log4j
Log4j 是 apache 的一個開源項目,創(chuàng)始人 Ceki Gulcu。
Log4j 應(yīng)該說是 Java 領(lǐng)域資格最老,應(yīng)用最廣的日志工具。從誕生之日到現(xiàn)在一直廣受業(yè)界歡迎。
Log4j 是高度可配置的,并可通過在運行時的外部文件配置。它根據(jù)記錄的優(yōu)先級別,并提供機制,以指示記錄信息到許多的目的地,諸如:數(shù)據(jù)庫,文件,控制臺,UNIX 系統(tǒng)日志等。
Log4j 中有三個主要組成部分:
loggers- 負(fù)責(zé)捕獲記錄信息。
appenders- 負(fù)責(zé)發(fā)布日志信息,以不同的首選目的地。
layouts- 負(fù)責(zé)格式化不同風(fēng)格的日志信息。
Logback
Logback 是由 log4j 創(chuàng)始人 Ceki Gulcu 設(shè)計的又一個開源日記組件,目標(biāo)是替代 log4j。
logback 當(dāng)前分成三個模塊:logback-core、logback-classic?和?logback-access。
logback-core?- 是其它兩個模塊的基礎(chǔ)模塊。
logback-classic?- 是 log4j 的一個 改良版本。此外?logback-classic?完整實現(xiàn) SLF4J API 使你可以很方便地更換成其它日記系統(tǒng)如 log4j 或 JDK14 Logging。
logback-access?- 訪問模塊與 Servlet 容器集成提供通過 Http 來訪問日記的功能。
Log4j2
按照官方的說法,Log4j2 是 Log4j 和 Logback 的替代。
Log4j2 架構(gòu):
Log4j vs Logback vs Log4j2
按照官方的說法,Log4j2 大大優(yōu)于 Log4j 和 Logback。
那么,Log4j2 相比于先問世的 Log4j 和 Logback,它具有哪些優(yōu)勢呢?
Log4j2 旨在用作審計日志記錄框架。 Log4j 1.x 和 Logback 都會在重新配置時丟失事件。 Log4j 2 不會。在 Logback 中,Appender 中的異常永遠(yuǎn)不會對應(yīng)用程序可見。在 Log4j 中,可以將 Appender 配置為允許異常滲透到應(yīng)用程序。
Log4j2 在多線程場景中,異步 Loggers?的吞吐量比 Log4j 1.x 和 Logback 高 10 倍,延遲低幾個數(shù)量級。
Log4j2 對于獨立應(yīng)用程序是無垃圾的,對于穩(wěn)定狀態(tài)日志記錄期間的 Web 應(yīng)用程序來說是低垃圾。這減少了垃圾收集器的壓力,并且可以提供更好的響應(yīng)時間性能。
Log4j2 使用插件系統(tǒng),通過添加新的 Appender、Filter、Layout、Lookup 和 Pattern Converter,可以非常輕松地擴(kuò)展框架,而無需對 Log4j 進(jìn)行任何更改。
由于插件系統(tǒng)配置更簡單。配置中的條目不需要指定類名。
支持自定義日志等級。
支持?lambda 表達(dá)式。
支持消息對象。
Log4j 和 Logback 的 Layout 返回的是字符串,而 Log4j2 返回的是二進(jìn)制數(shù)組,這使得它能被各種 Appender 使用。
Syslog Appender 支持 TCP 和 UDP 并且支持 BSD 系統(tǒng)日志。
Log4j2 利用 Java5 并發(fā)特性,盡量小粒度的使用鎖,減少鎖的開銷。
日志門面
何謂日志門面?
日志門面是對不同日志框架提供的一個 API 封裝,可以在部署的時候不修改任何配置即可接入一種日志實現(xiàn)方案。
common-logging
common-logging 是 apache 的一個開源項目。也稱Jakarta Commons Logging,縮寫 JCL。
common-logging 的功能是提供日志功能的 API 接口,本身并不提供日志的具體實現(xiàn)(當(dāng)然,common-logging 內(nèi)部有一個 Simple logger 的簡單實現(xiàn),但是功能很弱,直接忽略),而是在運行時動態(tài)的綁定日志實現(xiàn)組件來工作(如 log4j、java.util.loggin)。
slf4j
全稱為 Simple Logging Facade for Java,即 java 簡單日志門面。
什么,作者又是 Ceki Gulcu!這位大神寫了 Log4j、Logback 和 slf4j,專注日志組件開發(fā)五百年,一直只能超越自己。
類似于 Common-Logging,slf4j 是對不同日志框架提供的一個 API 封裝,可以在部署的時候不修改任何配置即可接入一種日志實現(xiàn)方案。但是,slf4j 在編譯時靜態(tài)綁定真正的 Log 庫。使用 SLF4J 時,如果你需要使用某一種日志實現(xiàn),那么你必須選擇正確的 SLF4J 的 jar 包的集合(各種橋接包)。
common-logging vs slf4j
slf4j 庫類似于 Apache Common-Logging。但是,他在編譯時靜態(tài)綁定真正的日志庫。這點似乎很麻煩,其實也不過是導(dǎo)入橋接 jar 包而已。
slf4j 一大亮點是提供了更方便的日志記錄方式:
不需要使用logger.isDebugEnabled()來解決日志因為字符拼接產(chǎn)生的性能問題。slf4j 的方式是使用{}作為字符串替換符,形式如下:
logger.debug("id: {}, name: {} ", id, name);
總結(jié)
綜上所述,使用 slf4j + Logback 可謂是目前最理想的日志解決方案了。
接下來,就是如何在項目中實施了。
實施日志解決方案
使用日志解決方案基本可分為三步:
引入 jar 包
配置
使用 API
常見的各種日志解決方案的第 2 步和第 3 步基本一樣,實施上的差別主要在第 1 步,也就是使用不同的庫。
引入 jar 包
這里首選推薦使用 slf4j + logback 的組合。
如果你習(xí)慣了 common-logging,可以選擇 common-logging+log4j。
強烈建議不要直接使用日志實現(xiàn)組件(logback、log4j、java.util.logging),理由前面也說過,就是無法靈活替換日志庫。
還有一種情況:你的老項目使用了 common-logging,或是直接使用日志實現(xiàn)組件。如果修改老的代碼,工作量太大,需要兼容處理。在下文,都將看到各種應(yīng)對方法。
注:據(jù)我所知,當(dāng)前仍沒有方法可以將 slf4j 橋接到 common-logging。如果我孤陋寡聞了,請不吝賜教。
slf4j 直接綁定日志組件
slf4j + logback
添加依賴到 pom.xml 中即可。
logback-classic-1.0.13.jar會自動將slf4j-api-1.7.21.jar和logback-core-1.0.13.jar也添加到你的項目中。
<dependency>
? <groupId>ch.qos.logback</groupId>
? <artifactId>logback-classic</artifactId>
? <version>1.0.13</version>
</dependency>
slf4j + log4j
添加依賴到 pom.xml 中即可。
slf4j-log4j12-1.7.21.jar會自動將slf4j-api-1.7.21.jar和log4j-1.2.17.jar也添加到你的項目中。
<dependency>
? <groupId>org.slf4j</groupId>
? <artifactId>slf4j-log4j12</artifactId>
? <version>1.7.21</version>
</dependency>
slf4j + java.util.logging
添加依賴到 pom.xml 中即可。
slf4j-jdk14-1.7.21.jar會自動將slf4j-api-1.7.21.jar也添加到你的項目中。
<dependency>
? <groupId>org.slf4j</groupId>
? <artifactId>slf4j-jdk14</artifactId>
? <version>1.7.21</version>
</dependency>
slf4j 兼容非 slf4j 日志組件
在介紹解決方案前,先提一個概念——橋接
什么是橋接呢
假如你正在開發(fā)應(yīng)用程序所調(diào)用的組件當(dāng)中已經(jīng)使用了 common-logging,這時你需要 jcl-over-slf4j.jar 把日志信息輸出重定向到 slf4j-api,slf4j-api 再去調(diào)用 slf4j 實際依賴的日志組件。這個過程稱為橋接。下圖是官方的 slf4j 橋接策略圖:
從圖中應(yīng)該可以看出,無論你的老項目中使用的是 common-logging 或是直接使用 log4j、java.util.logging,都可以使用對應(yīng)的橋接 jar 包來解決兼容問題。
slf4j 兼容 common-logging
<dependency>
? <groupId>org.slf4j</groupId>
? <artifactId>jcl-over-slf4j</artifactId>
? <version>1.7.12</version>
</dependency>
slf4j 兼容 log4j
<dependency>
? ? <groupId>org.slf4j</groupId>
? ? <artifactId>log4j-over-slf4j</artifactId>
? ? <version>1.7.12</version>
</dependency>
slf4j 兼容 java.util.logging
<dependency>
? ? <groupId>org.slf4j</groupId>
? ? <artifactId>jul-to-slf4j</artifactId>
? ? <version>1.7.12</version>
</dependency>
spring 集成 slf4j
做 java web 開發(fā),基本離不開 spring 框架。很遺憾,spring 使用的日志解決方案是 common-logging + log4j。
所以,你需要一個橋接 jar 包:logback-ext-spring。
<dependency>
? <groupId>ch.qos.logback</groupId>
? <artifactId>logback-classic</artifactId>
? <version>1.1.3</version>
</dependency>
<dependency>
? <groupId>org.logback-extensions</groupId>
? <artifactId>logback-ext-spring</artifactId>
? <version>0.1.2</version>
</dependency>
<dependency>
? <groupId>org.slf4j</groupId>
? <artifactId>jcl-over-slf4j</artifactId>
? <version>1.7.12</version>
</dependency>
common-logging 綁定日志組件
common-logging + log4j
添加依賴到 pom.xml 中即可。
<dependency>
? <groupId>commons-logging</groupId>
? <artifactId>commons-logging</artifactId>
? <version>1.2</version>
</dependency>
<dependency>
? <groupId>log4j</groupId>
? <artifactId>log4j</artifactId>
? <version>1.2.17</version>
</dependency>
使用 API
slf4j 用法
使用 slf4j 的 API 很簡單。使用LoggerFactory初始化一個Logger實例,然后調(diào)用 Logger 對應(yīng)的打印等級函數(shù)就行了。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class App {
? ? private static final Logger log = LoggerFactory.getLogger(App.class);
? ? public static void main(String[] args) {
? ? ? ? String msg = "print log, current level: {}";
? ? ? ? log.trace(msg, "trace");
? ? ? ? log.debug(msg, "debug");
? ? ? ? log.info(msg, "info");
? ? ? ? log.warn(msg, "warn");
? ? ? ? log.error(msg, "error");
? ? }
}
common-logging 用法
common-logging 用法和 slf4j 幾乎一樣,但是支持的打印等級多了一個更高級別的:fatal。
此外,common-logging 不支持{}替換參數(shù),你只能選擇拼接字符串這種方式了。
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JclTest {
? ? private static final Log log = LogFactory.getLog(JclTest.class);
? ? public static void main(String[] args) {
? ? ? ? String msg = "print log, current level: ";
? ? ? ? log.trace(msg + "trace");
? ? ? ? log.debug(msg + "debug");
? ? ? ? log.info(msg + "info");
? ? ? ? log.warn(msg + "warn");
? ? ? ? log.error(msg + "error");
? ? ? ? log.fatal(msg + "fatal");
? ? }
}
log4j2 配置
log4j2 基本配置形式如下:
<?xml version="1.0" encoding="UTF-8"?>;
<Configuration>
? <Properties>
? ? <Property name="name1">value</property>
? ? <Property name="name2" value="value2"/>
? </Properties>
? <Filter type="type" ... />
? <Appenders>
? ? <Appender type="type" name="name">
? ? ? <Filter type="type" ... />
? ? </Appender>
? ? ...
? </Appenders>
? <Loggers>
? ? <Logger name="name1">
? ? ? <Filter type="type" ... />
? ? </Logger>
? ? ...
? ? <Root level="level">
? ? ? <AppenderRef ref="name"/>
? ? </Root>
? </Loggers>
</Configuration>
配置示例:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" strict="true" name="XMLConfigTest"
? ? ? ? ? ? ? packages="org.apache.logging.log4j.test">
? <Properties>
? ? <Property name="filename">target/test.log</Property>
? </Properties>
? <Filter type="ThresholdFilter" level="trace"/>
? <Appenders>
? ? <Appender type="Console" name="STDOUT">
? ? ? <Layout type="PatternLayout" pattern="%m MDC%X%n"/>
? ? ? <Filters>
? ? ? ? <Filter type="MarkerFilter" marker="FLOW" onMatch="DENY" onMismatch="NEUTRAL"/>
? ? ? ? <Filter type="MarkerFilter" marker="EXCEPTION" onMatch="DENY" onMismatch="ACCEPT"/>
? ? ? </Filters>
? ? </Appender>
? ? <Appender type="Console" name="FLOW">
? ? ? <Layout type="PatternLayout" pattern="%C{1}.%M %m %ex%n"/><!-- class and line number -->
? ? ? <Filters>
? ? ? ? <Filter type="MarkerFilter" marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
? ? ? ? <Filter type="MarkerFilter" marker="EXCEPTION" onMatch="ACCEPT" onMismatch="DENY"/>
? ? ? </Filters>
? ? </Appender>
? ? <Appender type="File" name="File" fileName="${filename}">
? ? ? <Layout type="PatternLayout">
? ? ? ? <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
? ? ? </Layout>
? ? </Appender>
? </Appenders>
? <Loggers>
? ? <Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
? ? ? <Filter type="ThreadContextMapFilter">
? ? ? ? <KeyValuePair key="test" value="123"/>
? ? ? </Filter>
? ? ? <AppenderRef ref="STDOUT"/>
? ? </Logger>
? ? <Logger name="org.apache.logging.log4j.test2" level="debug" additivity="false">
? ? ? <AppenderRef ref="File"/>
? ? </Logger>
? ? <Root level="trace">
? ? ? <AppenderRef ref="STDOUT"/>
? ? </Root>
? </Loggers>
</Configuration>
logback 配置
<configuration>
一,作用:<configuration>?是 logback 配置文件的根元素。
二,要點
1.它有?<appender>、<logger>、<root>?三個子元素。
<appender>
一,作用:將記錄日志的任務(wù)委托給名為 appender 的組件。
二,要點
1.可以配置零個或多個。
2.它有?<file>、<filter>、<layout>、<encoder>?四個子元素。
三,屬性
1.name:設(shè)置 appender 名稱。
2.class:設(shè)置具體的實例化類。
<file>
一,作用:設(shè)置日志文件路徑。
<filter>
一,作用:設(shè)置過濾器。
二,要點
1.可以配置零個或多個。
<layout>
一,作用:設(shè)置 appender。
二,要點
1.可以配置零個或一個。
三,屬性
1.class:設(shè)置具體的實例化類。
<encoder>
一,作用:設(shè)置編碼。
二,要點
1.可以配置零個或多個。
三,屬性
1.class:設(shè)置具體的實例化類。
<logger>
一,作用:設(shè)置 logger。
二,要點
1.可以配置零個或多個。
三,屬性
1.name
l2.evel:設(shè)置日志級別。不區(qū)分大小寫??蛇x值:TRACE、DEBUG、INFO、WARN、ERROR、ALL、OFF。
3.additivity:可選值:true 或 false。
<appender-ref>
一,作用:appender 引用。
二,要點
1.可以配置零個或多個。
<root>
一,作用:設(shè)置根 logger。
二,要點
1.只能配置一個。
2.除了 level,不支持任何屬性。level 屬性和?<logger>?中的相同。
3.有一個子元素?<appender-ref>,與?<logger>?中的相同。
完整的 logback.xml 參考示例
在下面的配置文件中,我為自己的項目代碼(根目錄:org.zp.notes.spring)設(shè)置了五種等級:
TRACE、DEBUG、INFO、WARN、ERROR,優(yōu)先級依次從低到高。
因為關(guān)注 spring 框架本身的一些信息,我增加了專門打印 spring WARN 及以上等級的日志。
<?xml version="1.0" encoding="UTF-8" ?>
<!-- logback中一共有5種有效級別,分別是TRACE、DEBUG、INFO、WARN、ERROR,優(yōu)先級依次從低到高 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
? <property name="DIR_NAME" value="spring-helloworld"/>
? <!-- 將記錄日志打印到控制臺 -->
? <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
? ? <encoder>
? ? ? <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
? ? </encoder>
? </appender>
? <!-- RollingFileAppender begin -->
? <appender name="ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
? ? <!-- 根據(jù)時間來制定滾動策略 -->
? ? <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
? ? ? <fileNamePattern>${user.dir}/logs/${DIR_NAME}/all.%d{yyyy-MM-dd}.log</fileNamePattern>
? ? ? <maxHistory>30</maxHistory>
? ? </rollingPolicy>
? ? <!-- 根據(jù)文件大小來制定滾動策略 -->
? ? <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
? ? ? <maxFileSize>30MB</maxFileSize>
? ? </triggeringPolicy>
? ? <encoder>
? ? ? <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
? ? </encoder>
? </appender>
? <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
? ? <!-- 根據(jù)時間來制定滾動策略 -->
? ? <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
? ? ? <fileNamePattern>${user.dir}/logs/${DIR_NAME}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
? ? ? <maxHistory>30</maxHistory>
? ? </rollingPolicy>
? ? <!-- 根據(jù)文件大小來制定滾動策略 -->
? ? <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
? ? ? <maxFileSize>10MB</maxFileSize>
? ? </triggeringPolicy>
? ? <filter class="ch.qos.logback.classic.filter.LevelFilter">
? ? ? <level>ERROR</level>
? ? ? <onMatch>ACCEPT</onMatch>
? ? ? <onMismatch>DENY</onMismatch>
? ? </filter>
? ? <encoder>
? ? ? <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
? ? </encoder>
? </appender>
? <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
? ? <!-- 根據(jù)時間來制定滾動策略 -->
? ? <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
? ? ? <fileNamePattern>${user.dir}/logs/${DIR_NAME}/warn.%d{yyyy-MM-dd}.log</fileNamePattern>
? ? ? <maxHistory>30</maxHistory>
? ? </rollingPolicy>
? ? <!-- 根據(jù)文件大小來制定滾動策略 -->
? ? <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
? ? ? <maxFileSize>10MB</maxFileSize>
? ? </triggeringPolicy>
? ? <filter class="ch.qos.logback.classic.filter.LevelFilter">
? ? ? <level>WARN</level>
? ? ? <onMatch>ACCEPT</onMatch>
? ? ? <onMismatch>DENY</onMismatch>
? ? </filter>
? ? <encoder>
? ? ? <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
? ? </encoder>
? </appender>
? <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
? ? <!-- 根據(jù)時間來制定滾動策略 -->
? ? <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
? ? ? <fileNamePattern>${user.dir}/logs/${DIR_NAME}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
? ? ? <maxHistory>30</maxHistory>
? ? </rollingPolicy>
? ? <!-- 根據(jù)文件大小來制定滾動策略 -->
? ? <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
? ? ? <maxFileSize>10MB</maxFileSize>
? ? </triggeringPolicy>
? ? <filter class="ch.qos.logback.classic.filter.LevelFilter">
? ? ? <level>INFO</level>
? ? ? <onMatch>ACCEPT</onMatch>
? ? ? <onMismatch>DENY</onMismatch>
? ? </filter>
? ? <encoder>
? ? ? <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
? ? </encoder>
? </appender>
? <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
? ? <!-- 根據(jù)時間來制定滾動策略 -->
? ? <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
? ? ? <fileNamePattern>${user.dir}/logs/${DIR_NAME}/debug.%d{yyyy-MM-dd}.log</fileNamePattern>
? ? ? <maxHistory>30</maxHistory>
? ? </rollingPolicy>
? ? <!-- 根據(jù)文件大小來制定滾動策略 -->
? ? <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
? ? ? <maxFileSize>10MB</maxFileSize>
? ? </triggeringPolicy>
? ? <filter class="ch.qos.logback.classic.filter.LevelFilter">
? ? ? <level>DEBUG</level>
? ? ? <onMatch>ACCEPT</onMatch>
? ? ? <onMismatch>DENY</onMismatch>
? ? </filter>
? ? <encoder>
? ? ? <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
? ? </encoder>
? </appender>
? <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
? ? <!-- 根據(jù)時間來制定滾動策略 -->
? ? <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
? ? ? <fileNamePattern>${user.dir}/logs/${DIR_NAME}/trace.%d{yyyy-MM-dd}.log</fileNamePattern>
? ? ? <maxHistory>30</maxHistory>
? ? </rollingPolicy>
? ? <!-- 根據(jù)文件大小來制定滾動策略 -->
? ? <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
? ? ? <maxFileSize>10MB</maxFileSize>
? ? </triggeringPolicy>
? ? <filter class="ch.qos.logback.classic.filter.LevelFilter">
? ? ? <level>TRACE</level>
? ? ? <onMatch>ACCEPT</onMatch>
? ? ? <onMismatch>DENY</onMismatch>
? ? </filter>
? ? <encoder>
? ? ? <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
? ? </encoder>
? </appender>
? <appender name="SPRING" class="ch.qos.logback.core.rolling.RollingFileAppender">
? ? <!-- 根據(jù)時間來制定滾動策略 -->
? ? <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
? ? ? <fileNamePattern>${user.dir}/logs/${DIR_NAME}/springframework.%d{yyyy-MM-dd}.log
? ? ? </fileNamePattern>
? ? ? <maxHistory>30</maxHistory>
? ? </rollingPolicy>
? ? <!-- 根據(jù)文件大小來制定滾動策略 -->
? ? <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
? ? ? <maxFileSize>10MB</maxFileSize>
? ? </triggeringPolicy>
? ? <encoder>
? ? ? <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
? ? </encoder>
? </appender>
? <!-- RollingFileAppender end -->
? <!-- logger begin -->
? <!-- 本項目的日志記錄,分級打印 -->
? <logger name="org.zp.notes.spring" level="TRACE" additivity="false">
? ? <appender-ref ref="STDOUT"/>
? ? <appender-ref ref="ERROR"/>
? ? <appender-ref ref="WARN"/>
? ? <appender-ref ref="INFO"/>
? ? <appender-ref ref="DEBUG"/>
? ? <appender-ref ref="TRACE"/>
? </logger>
? <!-- SPRING框架日志 -->
? <logger name="org.springframework" level="WARN" additivity="false">
? ? <appender-ref ref="SPRING"/>
? </logger>
? <root level="TRACE">
? ? <appender-ref ref="ALL"/>
? </root>
? <!-- logger end -->
</configuration>
log4j 配置
完整的 log4j.xml 參考示例
log4j 的配置文件一般有 xml 格式或 properties 格式。這里為了和 logback.xml 做個對比,就不介紹 properties 了,其實也沒太大差別。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
? <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
? ? <layout class="org.apache.log4j.PatternLayout">
? ? ? <param name="ConversionPattern"
? ? ? ? ? ? value="%d{yyyy-MM-dd HH:mm:ss,SSS\} [%-5p] [%t] %c{36\}.%M - %m%n"/>
? ? </layout>
? ? <!--過濾器設(shè)置輸出的級別-->
? ? <filter class="org.apache.log4j.varia.LevelRangeFilter">
? ? ? <param name="levelMin" value="debug"/>
? ? ? <param name="levelMax" value="fatal"/>
? ? ? <param name="AcceptOnMatch" value="true"/>
? ? </filter>
? </appender>
? <appender name="ALL" class="org.apache.log4j.DailyRollingFileAppender">
? ? <param name="File" value="${user.dir}/logs/spring-common/jcl/all"/>
? ? <param name="Append" value="true"/>
? ? <!-- 每天重新生成日志文件 -->
? ? <param name="DatePattern" value="'-'yyyy-MM-dd'.log'"/>
? ? <!-- 每小時重新生成日志文件 -->
? ? <!--<param name="DatePattern" value="'-'yyyy-MM-dd-HH'.log'"/>-->
? ? <layout class="org.apache.log4j.PatternLayout">
? ? ? <param name="ConversionPattern"
? ? ? ? ? ? value="%d{yyyy-MM-dd HH:mm:ss,SSS\} [%-5p] [%t] %c{36\}.%M - %m%n"/>
? ? </layout>
? </appender>
? <!-- 指定logger的設(shè)置,additivity指示是否遵循缺省的繼承機制-->
? <logger name="org.zp.notes.spring" additivity="false">
? ? <level value="error"/>
? ? <appender-ref ref="STDOUT"/>
? ? <appender-ref ref="ALL"/>
? </logger>
? <!-- 根logger的設(shè)置-->
? <root>
? ? <level value="warn"/>
? ? <appender-ref ref="STDOUT"/>
? </root>
</log4j:configuration>
參考
slf4 官方文檔
logback 官方文檔
log4j 官方文檔
commons-logging 官方文檔