后端开发技术之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.mzph.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;其余的基本…