第一章 日志原理
1.1 log發展歷史
從JDK1.4開始提供java.until.logging,后來大佬發現JUL太難用了,就自己手擼了個log4j,后來log4j發現安全漏洞,加上代碼結構問題難以維護,于是從1.2就停止更新log4j,并又重新手擼了個log4j2,后來這個大佬手擼了一個性能更高、功能更全的logback,從此,這個大佬構建了log的世界,也創造了最常見的日志框架:JUL、log4j、log4j2、logback。
1.2 SLF4J接口
SLF4J:Simple Logging Facade for Java
目前已經提及的四個日志框架,如果我們想用來記錄日志的話,需要完成它們必要的配置,并且在代碼中獲取Logger,打印日志。
// 使用log4j,需要log4j.jar
import org.apache.log4j.Logger;
Logger logger = Logger.getLogger(Test.class);
logger.info("Hello World!");// 使用log4j2,需要log4j-api.jar、log4j-core.jar
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Logger logger = LogManager.getLogger(Test.class);
logger.info("Hello World!");// logback,需要logback-classic.jar、logback-core.jar
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
Logger logger = new LoggerContext().getLogger(Test.class);
logger.info("Hello World!");// java.until.logging,簡稱jul
import java.util.logging.Logger;
Logger logger = Logger.getLogger("java.Test");
從上面不難看出,使用不同的日志框架,就要引入不同的jar包,使用不同的代碼獲取Logger。假設一個項目在漫長的升級過程中,想從jul升級到logback,還得需要修改代碼。如果100個class中使用了jul,就得修改100個地方,這是多么一個繁瑣的工作。于是Apache Commons Logging出現了。Common-logging提供了一個日志入口,稱作"門面日志",即它不負責寫日志,而是提供用一個統一的接口,通過jar來決定使用的日志框架,這樣就不要再更換框架的時候再修改代碼了。后來開發了log4j的大佬在嫌棄Common-logging難用之后又開發了同樣功能的slf4j,今天就拿slf4j講述門面日志。
使用slf4j的代碼如下:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Logger logger = LoggerFactory.getLogger(Test.class);
logger.info("Hello World!")
那么slf4j如何決定使用哪個框架日志呢?如slf4j官方圖所示:
這就是slf4j和其他框架的組合,使用slf4j需要首先導入slf4j-api.jar,和log4j配合,你就要導入log4j.jar,以及他們之間的橋接包slf4j-log412.jar。這個官方圖美中不足的地方是,沒有log4j2的配合方式,和log4j2配合需要導入橋接包log4j-slf4j-impl.jar和log4j2的**log4j-api.jar、log4j-core.jar。logback只需要導入logback-classic和logback-core.jar**即可,不需要橋接包。
“Class path contains multiple SLF4J bindings.” 在使用slf4j的時候會遇到以上的報告信息。我也曾遇到過web服務因為slf4j問題啟動失敗。究其根本是因為logback-classic、log4j-slf4j-impl、slf4j-log412、slf4j-jdk這些jar不能同時存在。他們都實現了StaticLoggerBinder類而導致沖突,slf4j無法確定到底用哪個日志框架。
第二章 SLF4J門面與其他日志框架
參考:https://www.slf4j.org/manual.html
2.1 JUL和SLF4J
JUL:是Java平臺自帶的日志系統,即java.util.logging包提供的日志功能。
2.1.1 引入依賴
<!-- java.util.logging適配slf4j -->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-jdk14</artifactId><version>2.0.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.17</version>
</dependency>
2.1.1 配置文件
logging.properties
# 配置根日志記錄器的級別和處理器
.level = INFO
handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler# 配置文件處理器
java.util.logging.FileHandler.level = INFO
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
java.util.logging.FileHandler.append = true# 配置控制臺處理器
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter# 配置特定包的日志級別
com.example.level = error# 配置特定類的日志級別(如果需要的話)
# com.example.myapp.MyClass.level = FINE# 全局格式化器配置(可選,通常已在處理器中指定)
# java.util.logging.ConsoleFormatter = java.util.logging.SimpleFormatter
# java.util.logging.XMLFormatter.limit = 5000
# 注意:全局格式化器配置通常不是必需的,因為可以在處理器級別指定# 注意:%h 表示用戶主目錄,%u 表示唯一標識符(用于避免文件名沖突)
# limit 屬性指定文件大小限制(以字節為單位),count 屬性指定保留的舊文件數量
2.1.3 案例演示
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class MyApp {private static final Logger logger = LoggerFactory.getLogger(MyApp.class);public static void main(String[] args) {logger.info("這是info級別的日志信息");logger.error("這是error級別的日志信息");}
}
2.2 log4j和SLF4J
接口包、橋接包、log4j
2.2.1 引入依賴
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>2.0.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
2.2.2 配置文件
log4j.properties
# 設置根日志級別為INFO,輸出到控制臺和文件
log4j.rootLogger=INFO, CONSOLE, FILE# 控制臺輸出配置
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d [%t] %-5p %c - %m%n# 文件輸出配置
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./logfile.log
log4j.appender.FILE.MaxFileSize=10MB
log4j.appender.FILE.MaxBackupIndex=10
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
log4j.appender.FILE.encoding=UTF-8
或者log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"><!-- 定義根記錄器的級別和輸出目標 --><root><priority value="INFO" /><appender-ref ref="FILE" /><appender-ref ref="CONSOLE" /></root><!-- 配置文件輸出 --><appender name="FILE" class="org.apache.log4j.RollingFileAppender"><param name="File" value="/path/to/logfile.log" /><param name="MaxFileSize" value="10MB" /><param name="MaxBackupIndex" value="10" /><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" /></layout></appender><!-- 配置控制臺輸出 --><appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" /></layout></appender><!-- 可選:為特定包或類設置日志級別 --><!--<logger name="com.example.myapp" additivity="false"><level value="debug" /><appender-ref ref="FILE" /></logger>--></log4j:configuration>
2.2.3 案例演示
import org.apache.log4j.Logger;public class Main {private static final Logger logger = Logger.getLogger(Main.class);public static void main(String[] args) {logger.debug("這是一個debug級別的日志消息");logger.info("這是一個info級別的日志消息");logger.warn("這是一個warn級別的日志消息");logger.error("這是一個error級別的日志消息");}
}
2.3 reload4j和SLF4J
接口包、橋接包、reload4j包
reload4j是Log4j 1.2.17的一個分支,旨在解決Log4j中最為迫切的安全問題。它設計成一種即插即用的解決方案,可以無縫切換,直接替換庫文件,無需代碼更改,就能簡化升級過程。
你需要在你的pom.xml文件中添加reload4j和SLF4J的依賴。由于reload4j是log4j 1.2.7的替代品,并且與SLF4J兼容
2.5.1 引入依賴
<dependencies>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.17</version>
</dependency>
<!-- reload4j作為log4j 1.2.7的替代品 -->
<!-- https://mvnrepository.com/artifact/ch.qos.reload4j/reload4j -->
<dependency><groupId>ch.qos.reload4j</groupId><artifactId>reload4j</artifactId><version>1.2.26</version>
</dependency>
<!-- SLF4J到reload4j的綁定 -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-reload4j</artifactId><version>2.0.17</version><scope>compile</scope>
</dependency>
</dependencies>
2.5.2 配置文件
reload4j的配置文件與log4j 1.2.7的配置文件兼容,因此你可以使用相同的log4j.properties文件來配置reload4j
# 設置根Logger的級別和Appender
log4j.rootLogger=DEBUG, stdout, file# 控制臺Appender配置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n# 文件Appender配置
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=app.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n
2.5.3 案例演示
package com.example;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Main {// 獲取一個Logger實例,通常使用當前類的Class對象作為參數private static final Logger logger = LoggerFactory.getLogger(Main.class);public static void main(String[] args) {// 記錄不同級別的日志信息logger.trace("This is a TRACE level message");logger.debug("This is a DEBUG level message");logger.info("This is an INFO level message");logger.warn("This is a WARN level message");logger.error("This is an ERROR level message");// 記錄包含變量信息的日志String userName = "JohnDoe";int age = 30;logger.info("User {} is {} years old.", userName, age);// 記錄異常信息try {int result = 10 / 0; // 這將引發一個ArithmeticException} catch (ArithmeticException e) {logger.error("An arithmetic error occurred: {}", e.getMessage(), e);}}
}
2.4 log4j2和SLF4J
Log4j2是Apache Log4j的升級版,提供了強大的日志記錄功能
- org.apache.logging.log4j:log4j-core:2.24.2
- org.apache.logging.log4j:log4j-api:2.24.2
根據依賴。我們需要接口包、橋接包、log4j2本身包。但是我們發現log4j-slf4j2-impl依賴其他包。因此可以簡化。只需引入log4j-slf4j2-impl這一個包即可。
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j2-impl -->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j2-impl</artifactId><version>2.24.3</version><scope>compile</scope>
</dependency>
2.3.1 引入依賴
log4j-core包含了log4j-api一個頂兩
<dependencies>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j2-impl -->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j2-impl</artifactId><version>2.24.3</version><scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.24.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.24.3</version>
</dependency>
</dependencies>
2.3.2 配置文件
log4j2.properties
# 設置根日志級別為 INFO,并指定日志輸出到控制臺和文件
rootLogger.level = info
rootLogger.appenderRefs = stdout, file
rootLogger.appenderRef.stdout.ref = Console
rootLogger.appenderRef.file.ref = File# 控制臺日志配置
appender.stdout.type = Console
appender.stdout.name = Console
appender.stdout.layout.type = PatternLayout
appender.stdout.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n# 文件日志配置
appender.file.type = File
appender.file.name = File
appender.file.fileName = logs/app.log
appender.file.layout.type = PatternLayout
appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n# 日志文件滾動策略配置(可選)
appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName = logs/app-rolling.log
appender.rolling.filePattern = logs/app-rolling-%d{yyyy-MM-dd}.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 30# 將滾動日志添加到根日志記錄器(可選)
rootLogger.appenderRef.rolling.ref = RollingFile
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"><Appenders><!-- Console Appender --><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"/></Console><!-- File Appender --><File name="File" fileName="logs/app.log"><PatternLayout><Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</Pattern></PatternLayout></File></Appenders><Loggers><!-- Root Logger --><Root level="debug"><AppenderRef ref="Console"/><AppenderRef ref="File"/></Root><!-- Example Logger for a specific package --><Logger name="com.example" level="info" additivity="false"><AppenderRef ref="Console"/><AppenderRef ref="File"/></Logger></Loggers>
</Configuration>
2.3.3 案例演示
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Slf4jExample {private static final Logger logger = LoggerFactory.getLogger(Slf4jExample.class);public static void main(String[] args) {logger.error("This is an error message using SLF4J");logger.info("This is an info message using SLF4J");logger.debug("This is a debug message using SLF4J");}
}
2.5 logback和SLF4J
2.4.1 引入依賴
我們只需要引入logback-classic另外兩個就自動引入了。
<dependencies><!-- SLF4J API --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.17</version> </dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.5.18</version><scope>compile</scope>
</dependency>
</dependencies>
2.4.2 配置文件
Logback通常會在類路徑下尋找名為logback.xml的配置文件來配置日志記錄行為
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!-- 控制臺Appender --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 文件Appender --><appender name="FILE" class="ch.qos.logback.core.FileAppender"><file>app.log</file><append>true</append><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- Root Logger配置 --><root level="debug"><appender-ref ref="STDOUT" /><appender-ref ref="FILE" /></root>
</configuration>
2.4.3 案例演示
package com.example;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Main {// 獲取一個Logger實例,通常使用當前類的Class對象作為參數private static final Logger logger = LoggerFactory.getLogger(Main.class);public static void main(String[] args) {// 記錄不同級別的日志信息logger.trace("This is a TRACE level message");logger.debug("This is a DEBUG level message");logger.info("This is an INFO level message");logger.warn("This is a WARN level message");logger.error("This is an ERROR level message");// 記錄包含變量信息的日志String userName = "JohnDoe";int age = 30;logger.info("User {} is {} years old.", userName, age);// 記錄異常信息try {int result = 10 / 0; // 這將引發一個ArithmeticException} catch (ArithmeticException e) {logger.error("An arithmetic error occurred: {}", e.getMessage(), e);}}
}
2.6 slf4j-simpl自帶
slf4j-api-2.0.16.jar和 slf4j-simple-2.0.16.jar
SLF4J(Simple Logging Facade for Java)是一個為Java平臺上的多種日志框架提供通用接口的日志門面。通過SLF4J,開發者可以在不修改代碼的情況下輕松地切換底層日志實現。以下是一個使用slf4j-api-2.0.17.jar
和slf4j-simple-2.0.17.jar
的案例,展示了如何配置和使用這兩個jar包進行日志記錄。
假設我們正在開發一個Java應用程序,并且希望使用SLF4J作為日志門面,同時使用SLF4J自帶的簡單日志實現slf4j-simple
作為日志后端。
2.6.1 添加依賴
<dependencies><!-- SLF4J API --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.17</version></dependency><!-- SLF4J Simple Binding --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>2.0.17</version></dependency>
</dependencies>
2.6.2 配置文件
slf4j-simple
提供了簡單的日志配置選項,默認情況下會將日志輸出到標準輸出(控制臺)。如果需要自定義日志配置(如日志級別、輸出格式等),可以通過創建一個名為simplelogger.properties
的配置文件來實現。以下是一個示例配置文件:
# 設置默認的日志級別為INFO
org.slf4j.simpleLogger.defaultLogLevel=INFO# 為特定的類設置日志級別
org.slf4j.simpleLogger.log.Main=DEBUG# 設置日期和時間格式
org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss# 設置日志輸出格式
org.slf4j.simpleLogger.showDateTime=true
org.slf4j.simpleLogger.showLogName=true
org.slf4j.simpleLogger.showThreadName=true
org.slf4j.simpleLogger.levelInBrackets=true
#org.slf4j.simpleLogger.logFile=myapp.log
2.6.3 案例演示
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class MyApp {// 創建一個Logger實例private static final Logger logger = LoggerFactory.getLogger(MyApp.class);public static void main(String[] args) {// 記錄不同級別的日志信息logger.debug("This is a debug message");logger.info("This is an info message");logger.warn("This is a warn message");logger.error("This is an error message");// 記錄帶有參數的日志信息String name = "World";logger.info("Hello, {}", name);}
}
第三章 Commons Logging門面與其他日志框架
commons-logging總是能找到一個日志實現類,并且盡可能找到一個"最合適"的日志實現類.
3.1 原理
LogFactory作為log的工廠存在,使用動態查找機制進行log實例的獲取
①首先在classpath下尋找commons-logging.properties文件。如果找到,則使用其中定義的Log實現類;如果找不到,則在查找是否已定義系統環境變量org.apache.commons.logging.Log,找到則使用其定義的Log實現類;
②查看classpath中是否有Log4j的包,如果發現,則自動使用Log4j作為日志實現類;
③使用JDK自身的日志實現類(JDK1.4以后才有日志實現類);
④使用commons-logging自己提供的一個簡單的日志實現類SimpleLog;
上述步驟當LogFactory成功找到一個日志實現之后就會停止
org.apache.commons.logging.impl.Jdk14Logger,
org.apache.commons.logging.impl.Log4JLogger,
org.apache.commons.logging.impl.LogKitLogger,
org.apache.commons.logging.impl.SimpleLog,
org.apache.commons.logging.impl.NoOpLog
LogFactory使用動態查找機制進行日志實例化,執行順序為:common-logging.properties---->系統環境變量------->log4j—>jul—>simplelog---->nooplog
3.2 與Log4j結合
我們將配置Commons Logging以在運行時選擇Log4j作為日志實現,并編寫一個簡單的Java類來記錄日志。最悲觀的情況下也總能保證提供一個日志實現(SimpleLog)
3.2.1 引入依賴
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.3.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
3.2.2 配置文件
log4j.properties
# 配置根Logger
log4j.rootLogger=INFO, stdout, file# 配置控制臺輸出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n# 配置文件輸出
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=application.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=5
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
3.2.3 案例演示
package org.example;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;/*** @author whboy* @create 2025-05-02* @Description*/
public class Main {private static final Log logger = LogFactory.getLog(Main.class);public static void main(String[] args) {logger.info("This is an info message");logger.debug("This is a debug message");logger.error("This is an error message");}
}
3.3 與java.util.logging結合
Commons Logging與java.util.logging(JUL)的結合可以通過配置來實現,盡管在實際應用中,由于JUL的功能相對有限,開發者更傾向于將Commons Logging與更強大的日志框架(如Log4j或Logback)結合使用。不過,以下是一個簡單的案例,展示了如何將Commons Logging配置為使用JUL作為底層日志實現。
3.2.1 引入依賴
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.3.5</version>
</dependency>
通常不需要單獨引入JUL庫,因為JUL是Java標準庫的一部分,隨JDK一起提供
3.2.2 配置文件
我們不需要顯式配置commons-logging.properties
文件或設置系統屬性,因為JUL是JDK自帶的,Commons Logging會自動檢測到它并使用它(如果其他日志實現未被明確指定)
3.2.3 案例演示
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;public class Main {private static final Log logger = LogFactory.getLog(Main.class);public static void main(String[] args) {logger.info("This is an info message from Commons Logging using JUL");logger.debug("This is a debug message");logger.error("This is an error message");}
}
3.4 和Log4j2結合
以下是一個將Commons Logging與Log4j2結合的案例,展示了如何配置和使用這兩個框架來記錄日志。
在這個案例中,我們將使用Commons Logging作為日志門面,Log4j2作為實際的日志實現框架。我們將編寫一個簡單的Java類來演示如何記錄不同級別的日志信息,并通過配置Log4j2的XML文件來控制日志的輸出格式和目的地。
3.4.1 引入依賴
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.3.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.24.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-jcl -->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-jcl</artifactId><version>2.24.3</version>
</dependency>
3.4.2 配置文件
log4j2.properties
# 設置根日志級別為 INFO,并指定日志輸出到控制臺和文件
rootLogger.level = info
rootLogger.appenderRefs = stdout, file
rootLogger.appenderRef.stdout.ref = Console
rootLogger.appenderRef.file.ref = File# 控制臺日志配置
appender.stdout.type = Console
appender.stdout.name = Console
appender.stdout.layout.type = PatternLayout
appender.stdout.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n# 文件日志配置
appender.file.type = File
appender.file.name = File
appender.file.fileName = logs/app.log
appender.file.layout.type = PatternLayout
appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n# 日志文件滾動策略配置(可選)
appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName = logs/app-rolling.log
appender.rolling.filePattern = logs/app-rolling-%d{yyyy-MM-dd}.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 30# 將滾動日志添加到根日志記錄器(可選)
rootLogger.appenderRef.rolling.ref = RollingFile
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"><Appenders><!-- Console Appender --><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"/></Console><!-- File Appender --><File name="File" fileName="logs/app.log"><PatternLayout><Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</Pattern></PatternLayout></File></Appenders><Loggers><!-- Root Logger --><Root level="debug"><AppenderRef ref="Console"/><AppenderRef ref="File"/></Root><!-- Example Logger for a specific package --><Logger name="com.example" level="info" additivity="false"><AppenderRef ref="Console"/><AppenderRef ref="File"/></Logger></Loggers>
</Configuration>
3.4.3 案例演示
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;public class Main {private static final Log logger = LogFactory.getLog(Main.class);public static void main(String[] args) {logger.trace("This is a TRACE message");logger.debug("This is a DEBUG message");logger.info("This is an INFO message");logger.warn("This is a WARN message");logger.error("This is an ERROR message");logger.fatal("This is a FATAL message"); // Note: Commons Logging does not have a fatal level, but Log4j2 will handle it}
}
3.5 與logback結合
Commons Logging和Logback是Java日志記錄領域的兩種工具,雖然它們各自有獨立的用途和實現方式,但在某些情況下可以結合使用。以下是一個簡單的案例,展示了如何在項目中結合使用Commons Logging和Logback。
假設我們有一個Java Web項目,該項目使用Commons Logging作為日志記錄的接口,而實際的日志實現則使用Logback。我們的目標是配置項目,以便它能夠記錄日志到控制臺和文件中。
3.5.1 引入依賴
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.3.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.5.18</version><scope>compile</scope>
</dependency>
3.5.2 配置文件
Logback通常會在類路徑下尋找名為logback.xml的配置文件來配置日志記錄行為
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!-- 控制臺Appender --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 文件Appender --><appender name="FILE" class="ch.qos.logback.core.FileAppender"><file>app.log</file><append>true</append><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- Root Logger配置 --><root level="debug"><appender-ref ref="STDOUT" /><appender-ref ref="FILE" /></root>
</configuration>
3.5.3 案例演示
package org.example;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Main {// 獲取一個Logger實例,通常使用當前類的Class對象作為參數private static final Logger logger = LoggerFactory.getLogger(Main.class);public static void main(String[] args) {// 記錄不同級別的日志信息logger.trace("This is a TRACE level message");logger.debug("This is a DEBUG level message");logger.info("This is an INFO level message");logger.warn("This is a WARN level message");logger.error("This is an ERROR level message");// 記錄包含變量信息的日志String userName = "JohnDoe";int age = 30;logger.info("User {} is {} years old.", userName, age);// 記錄異常信息try {int result = 10 / 0; // 這將引發一個ArithmeticException} catch (ArithmeticException e) {logger.error("An arithmetic error occurred: {}", e.getMessage(), e);}}
}
3.6 與reload4j結合
要將Commons Logging與reload4j結合使用,通常是因為項目中已經使用了Commons Logging作為日志門面(facade),但希望將底層的日志實現替換為reload4j以利用其安全性增強和漏洞修復。
3.6.1 引入依賴
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.3.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.reload4j/reload4j -->
<dependency><groupId>ch.qos.reload4j</groupId><artifactId>reload4j</artifactId><version>1.2.26</version>
</dependency>
3.6.2 配置文件
reload4j的配置方式與Log4j 1.2.x相似。通常,你需要創建一個log4j.properties
或log4j.xml
配置文件,并在其中指定日志記錄器(logger)、附加器(appender)和布局(layout)等設置
以下是一個簡單的log4j.properties
配置文件示例:
# 設置根記錄器的級別和Appender
log4j.rootLogger=DEBUG, stdout, file# 配置控制臺輸出的Appender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n# 配置文件輸出的Appender
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=logs/app.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=5
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
3.6.3 案例演示
package org.example;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;/*** @author whboy* @create 2025-05-02* @Description*/public class Main {private static final Log log = LogFactory.getLog(Main.class);public static void main(String[] args) {log.info("This is an info message");log.debug("This is a debug message");log.error("This is an error message");}
}
附錄
門面和接口只能選擇一個。否則會沖突報錯。