后端開發技術之Log日志框架

第一章 日志原理

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官方圖所示:

image-20250501210624011

這就是slf4j和其他框架的組合,使用slf4j需要首先導入slf4j-api.jar,和log4j配合,你就要導入log4j.jar,以及他們之間的橋接包slf4j-log412.jar。這個官方圖美中不足的地方是,沒有log4j2的配合方式,和log4j2配合需要導入橋接包log4j-slf4j-impl.jar和log4j2的**log4j-api.jarlog4j-core.jar。logback只需要導入logback-classiclogback-core.jar**即可,不需要橋接包。

“Class path contains multiple SLF4J bindings.” 在使用slf4j的時候會遇到以上的報告信息。我也曾遇到過web服務因為slf4j問題啟動失敗。究其根本是因為logback-classic、log4j-slf4j-impl、slf4j-log412、slf4j-jdk這些jar不能同時存在。他們都實現了StaticLoggerBinder類而導致沖突,slf4j無法確定到底用哪個日志框架。

日志詳解.drawio

第二章 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這一個包即可。

image-20250502051824114

<!-- 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.jarslf4j-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

img

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.propertieslog4j.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");}
}

附錄

門面和接口只能選擇一個。否則會沖突報錯。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/81369.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81369.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/81369.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

美麗天天秒鏈動2+1源碼(新零售商城搭建)

什么是鏈動21模式&#xff1f; 鏈動21主要是建立團隊模式&#xff0c;同時快速提升銷量。是目前成員中速度最快的裂變模式。鏈動21模式合理合規&#xff0c;同時激勵用戶 公司的利潤分享機制&#xff0c;讓您在享受購物折扣的同時&#xff0c;也能促進并獲得客觀收益。 鏈動21模…

Python10天沖刺-設計模型之策略模式

策略模式是一種行為設計模式&#xff0c;它允許你在運行時動態地改變對象的行為。這種模式的核心思想是將一組相關的算法封裝在一起&#xff0c;并讓它們相互替換。 下面是使用 Python 實現策略模式的一個示例&#xff1a; 示例代碼 假設我們有一個簡單的購物車系統&#xf…

【CTFer成長之路】XSS的魔力

XSS闖關 level1 訪問url&#xff1a; http://c884a553-d874-4514-9c32-c19c7d7b6e1c.node3.buuoj.cn/level1?usernamexss 因為是xss&#xff0c;所以對傳參進行測試&#xff0c;修改?username1&#xff0c;進行訪問 會發現username參數傳入什么&#xff0c;welcome之后就…

自主機器人模擬系統

一、系統概述 本代碼實現了一個基于Pygame的2D自主機器人模擬系統&#xff0c;具備以下核心功能&#xff1a; 雙模式控制&#xff1a;支持手動控制&#xff08;WASD鍵&#xff09;和自動導航模式&#xff08;鼠標左鍵設定目標&#xff09; 智能路徑規劃&#xff1a;采用改進型…

快速上手非關系型數據庫-MongoDB

簡介 MongoDB 是一個基于文檔的 NoSQL 數據庫&#xff0c;由 MongoDB Inc. 開發。 NoSQL&#xff0c;指的是非關系型的數據庫。NoSQL有時也稱作Not Only SQL的縮寫&#xff0c;是對不同于傳統的關系型數據庫的數據庫管理系統的統稱。 MongoDB 的設計理念是為了應對大數據量、…

性能優化實踐:啟動優化方案

性能優化實踐&#xff1a;啟動優化方案 在Flutter應用開發中&#xff0c;啟動性能是用戶體驗的第一印象&#xff0c;也是應用性能優化的重要環節。本文將從理論到實踐&#xff0c;深入探討Flutter應用的啟動優化方案。 一、Flutter應用啟動流程分析 1. 啟動類型 冷啟動&…

在文本廢墟中打撈月光

在文本廢墟中打撈月光 ----再讀三三的《山頂上是海》之“暗室”所理 今天是2025年5月1日&#xff0c;傳統的“五一”小長假。當我早飯后“坐”在衛生間的那幾分鐘里&#xff0c;閨女和兒子就騎著家中僅有的兩輛電動車去了圖書館。我是該做些什么&#xff1f; 于是我左手拿著三…

C++之類和對象基礎

?向對象三?特性&#xff1a;封裝、繼承、多態 類和對象 一.類的定義1. 類的定義格式2.類域 二.實例化1.對象2.對象的大小 三.this指針 在 C 的世界里&#xff0c;類和對象構成了面向對象編程&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;的核心框架&…

計算機網絡——HTTP/IP 協議通俗入門詳解

HTTP/IP 協議通俗入門詳解 一、什么是 HTTP 協議&#xff1f;1. 基本定義2. HTTP 是怎么工作的&#xff1f; 二、HTTP 協議的特點三、HTTPS 是什么&#xff1f;它和 HTTP 有啥區別&#xff1f;1. HTTPS 概述2. HTTP vs HTTPS 四、HTTP 的通信過程步驟詳解&#xff1a; 五、常見…

使用 Java 實現一個簡單且高效的任務調度框架

目錄 一、任務調度系統概述 &#xff08;一&#xff09;任務調度的目標 &#xff08;二&#xff09;任務調度框架的關鍵組成 二、任務狀態設計 &#xff08;一&#xff09;任務狀態流轉設計 &#xff08;二&#xff09;任務表設計&#xff08;SQL&#xff09; 三、單機任…

基于GPT 模板開發智能寫作輔助應用

目錄 項目說明 1. 項目背景 2. 項目目標 3. 功能需求 4. 技術選型 項目結構 詳細代碼實現 前端代碼(client) client/src/main.js client/src/App.vue client/src/components/HistoryList.vue 后端代碼(server) server/app.js server/routes/api.js server/mo…

linux 使用nginx部署next.js項目,并使用pm2守護進程

前言 本文基于&#xff1a;操作系統 CentOS Stream 8 使用工具&#xff1a;Xshell8、Xftp8 服務器基礎環境&#xff1a; node - 請查看 linux安裝node并全局可用pm2 - 請查看 linux安裝pm2并全局可用nginx - 請查看 linux 使用nginx部署vue、react項目 所需服務器基礎環境&…

使用huggingface_hub需要注意的事項

在安裝huggingface_hub的時候要注意如果你的python是放在c盤下時記得用管理員模式命令行來安裝huggingface_hub&#xff0c;否則安裝過程會報錯&#xff0c;之后也不會有huggingface-cli命令。 如果安裝時因為沒有用管理員權限安裝而報錯了&#xff0c;可以先卸載huggingface-…

Spring MVC @RequestHeader 注解怎么用?

我們來詳細解釋一下 Spring MVC 中的 RequestHeader 注解。 RequestHeader 注解的作用 RequestHeader 注解用于將 HTTP 請求中的**請求頭&#xff08;Request Headers&#xff09;**的值綁定到 Controller 方法的參數上。 請求頭是 HTTP 請求的一部分&#xff0c;包含了關于…

Rust 學習筆記:關于結構體的例題

Rust 學習筆記&#xff1a;關于結構體的例題 Rust 學習筆記&#xff1a;關于結構體的例題下面的程序能通過編譯嗎&#xff1f;下面的程序能通過編譯嗎&#xff1f;下面的程序能通過編譯嗎&#xff1f;哪種說法最能描述 Display 和 Debug 特質之間的區別&#xff1f;下面哪個選項…

STM32 SPI通信協議

1. SPI協議概述 1.1 什么是SPI&#xff1f; SPI&#xff08;Serial Peripheral Interface&#xff09;是由摩托羅拉公司于1980年代提出的同步串行通信協議&#xff0c;主要用于短距離高速芯片間通信。作為四線制全雙工通信協議&#xff0c;它以簡單的硬件實現和高效的傳輸速率…

92.一個簡單的輸入與顯示示例 Maui例子 C#例子

一、關于項目命名的注意事項 在開發.NET MAUI項目時&#xff0c;項目命名是一個不可忽視的細節。如果你習慣了在C#控制臺或WPF項目中使用中文項目名稱&#xff0c;那么在.NET MAUI中&#xff0c;你可能會遇到一些問題。我之前就因為使用中文項目名稱而導致項目無法直接運行&am…

Locate 3D:Meta出品自監督學習3D定位方法

標題&#xff1a; Locate 3D: Real-World Object Localization via Self-Supervised Learning in 3D 摘要&#xff1a; 我們提出了 Locate 3D&#xff0c;這是一種可根據指代表達&#xff08;如“沙發和燈之間的小咖啡桌”&#xff09;在三維場景中定位物體的模型。Locate 3…

FastAPI 與數據庫交互示例

目錄 安裝必要的包完整代碼示例運行應用使用說明API 端點說明代碼解析 下面將創建一個簡單的 FastAPI 應用程序&#xff0c;演示如何與 SQLite 數據庫進行交互。這個例子包括創建、讀取、更新和刪除&#xff08;CRUD&#xff09;操作。 安裝必要的包 首先&#xff0c;需要安裝…

YOLO旋轉目標檢測之ONNX模型推理

YOLO旋轉檢測相較于目標檢測而言&#xff0c;其只是最后的輸出層網絡發生了改變&#xff0c;一個最明顯的區別便是&#xff1a;目標檢測的檢測框是xywh&#xff0c;而旋轉檢測則為xywha&#xff0c;其中&#xff0c;這個a代表angle&#xff0c;即旋轉角度&#xff0c;其余的基本…