Java日志框架是开发中记录和管理日志的重要工具,合理选择和使用日志组件能提升项目的可维护性和灵活性。
(1)日志门面
(2)日志实现
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>2.0.12version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.5.3version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>2.0.12version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-slf4j2-implartifactId>
<version>2.23.1version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.23.1version>
dependency>
若旧项目使用Log4j 1.x或JCL,可通过桥接器统一到SLF4J:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>2.0.12</version>
</dependency>
<!-- 排除原Log4j 1.x依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>2.0.12</version>
</dependency>
Apache Log4j 2 是 Java 社区中广泛使用的高性能日志框架,作为 Log4j 1.x 的升级版本,它在架构设计、性能和功能上进行了全面优化。
组件 | 作用 |
---|---|
Logger | 日志记录器,通过名称层次化继承配置(如 com.example.service)。 |
Appender | 定义日志输出目的地(控制台、文件、数据库、消息队列等)。 |
Layout | 指定日志格式(如时间、级别、类名、自定义字段)。 |
Filter | 过滤日志事件,决定是否输出或传递给下级组件。 |
内置级别(从低到高):TRACE < DEBUG < INFO < WARN < ERROR < FATAL。
支持自定义级别,但需谨慎使用以避免兼容性问题。
Log4j 2 默认加载类路径下的 log4j2.xml,也可通过 -Dlog4j.configurationFile
指定路径。
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
Console>
<RollingFile name="File" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="%d{ISO8601} %-5level [%t] %c{1.} - %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="100 MB"/>
Policies>
<DefaultRolloverStrategy max="10"/>
RollingFile>
Appenders>
<Loggers>
<Logger name="com.example.service" level="DEBUG" additivity="false">
<AppenderRef ref="File"/>
Logger>
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
Root>
Loggers>
Configuration>
配置参数说明:
日志级别:如果一条日志信息的级别大于等于配置文件的级别就记录。
输出源
格式
:,如 Console、File、RollingFile、Kafka 等。
:定义日志记录规则,可继承父 Logger 配置,additivity=“false” 阻止传递给父 Logger。
:在 Logger 或 Appender 中定义过滤条件(如 ThresholdFilter)。
log4j2配置节点说明:
全局异步(需 disruptor 依赖)
<Configuration>
<AsyncLogger name="com.example" level="DEBUG" includeLocation="true"/>
<AsyncRoot level="INFO">
<AppenderRef ref="Console"/>
</AsyncRoot>
</Configuration>
引入 Maven 依赖:
<dependency>
<groupId>com.lmaxgroupId>
<artifactId>disruptorartifactId>
<version>3.4.4version>
dependency>
使用 ThreadContext(即 MDC)添加上下文信息:
ThreadContext.put("requestId", UUID.randomUUID().toString());
logger.info("Processing request");
ThreadContext.clear();
在 Layout 中引用:
<PatternLayout pattern="%d{ISO8601} [%X{requestId}] %msg%n"/>
按条件动态路由日志到不同 Appender:
<Routing name="RoutingAppender">
<Routes pattern="$${ctx:logType}">
<Route key="AUDIT">
<File name="AuditLog" fileName="logs/audit.log"/>
</Route>
<Route key="DEBUG">
<Console name="Console"/>
</Route>
</Routes>
</Routing>
虽然Log4j2也是日志门面,因为它的日志实现功能非常强大,性能优越。所以大家一般还是将Log4j2看作是日志的实现。
<!-- Log4j2 门面API-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<!-- Log4j2 日志实现 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.14.1version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-slf4j-implartifactId>
<version>2.14.1version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-log4j2artifactId>
<version>3.2.0version>
dependency>
如果用到 Mybatis-Plus
也需要排除默认日志依赖。SLF4J: Class path contains multiple SLF4J providers.
SLF4J: Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider@e874448]
SLF4J: Found provider [org.apache.logging.slf4j.SLF4JServiceProvider@29b5cd00]
SLF4J: See https://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual provider is of type [ch.qos.logback.classic.spi.LogbackServiceProvider@e874448]
resource
目录下新建文件 log4j2-spring.xml
,如果自定义其他名称需在 application.yml
中配置:logging:
config: classpath:log4j2.xml
log4j2-spring.xml
模版:
<configuration monitorInterval="5">
<Properties>
<property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
<property name="FILE_PATH" value="更换为你的日志路径" />
<property name="FILE_NAME" value="更换为你的项目名" />
Properties>
<appenders>
<console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}"/>
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
console>
<File name="Filelog" fileName="${FILE_PATH}/test.log" append="false">
<PatternLayout pattern="${LOG_PATTERN}"/>
File>
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
Policies>
<DefaultRolloverStrategy max="15"/>
RollingFile>
<RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
Policies>
<DefaultRolloverStrategy max="15"/>
RollingFile>
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
Policies>
<DefaultRolloverStrategy max="15"/>
RollingFile>
appenders>
<loggers>
<logger name="org.mybatis" level="info" additivity="false">
<AppenderRef ref="Console"/>
logger>
<Logger name="org.springframework" level="info" additivity="false">
<AppenderRef ref="Console"/>
Logger>
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="Filelog"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
root>
loggers>
configuration>
slf4j
public class Demo {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);
public static void main(String... args) {
log.error("Something else is wrong here");
}
}
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.26version>
dependency>
import lombok.extern.log4j.Log4j2;
@Log4j2
public class LogTest {
public static void main(String[] args) {
log.info("this is info log");
log.error("this is error log");
log.debug("this is debug log");
log.warn("this is warn log");
log.trace("this is trace log");
log.fatal("this is fatal log");
}
}