Java常用日志框架介绍
Java提供了很多第三方的日志框架可供使用,按照现在的设计理念,一般把日志框架分成门面(Facade)
部分和具体实现(Implementation)
部分,门面(Facade)
提供了抽象的api规范,实现(Implementation)
负责实现api完成具体的日志记录功能。开发者在使用日志框架时使用的是门面提供的api,可以根据实际情况灵活的选择不同的api实现。
一、java.util.logging
1、概述
java.util.logging
是Java标准库自带的日志框架,使用时无需引入第三方依赖,提供的功能相对简单,一般不在实际项目中使用。
package com.demo;
import java.util.logging.Logger;class LoggingDemoApplicationTests {Logger logger = Logger.getLogger(LoggingDemoApplicationTests.class.getName());public static void main(String[] args) {logger.info("test logging.");}}
2、配置
java.util.logging
的配置文件是.proerties
文件,默认路径是$JAVA_HOME/lib/logging.proerties
,可以通过JVM参数或代码指定自定义的配置文件。
使用JVM参数-Djava.util.logging.config.file
指定:
java -Djava.util.logging.config.file=path/logging.properties mainApp.jar
使用代码指定:
package org.example;
public class JavaLoggingTest {public static void main(String[] args) {try (InputStream inputStream = Main.class.getResourceAsStream("config/logging.properties")) {LogManager.getLogManager().readConfiguration(inputStream);} catch (Exception e) {e.printStackTrace();}// 日志记录示例java.util.logging.Logger logger = java.util.logging.Logger.getLogger(Main.class.getName());logger.info("This is an info message.");}
}
配置文件内容:
# 全局日志级别
.level= INFO# 控制台处理器的日志级别
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter# 文件处理器的日志级别
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.SimpleFormatter# 自定义日志记录器的日志级别
com.example.JavaLoggingTest.level = FINE
二、commons-logging
1、概述
commons-logging
(JCL)提供了一轻量和独立于其他日志框架的个Log
接口,它给开发者提供了简单的日志抽象,允许开发者像使用插件一样选择具体的日志实现。
也就是说commons-logging
是一个日志门面,其不提供具体的日志实现。commons-logging
提供包装了其他日志API和后端的Log
接口的实现,包括Log4j2.x
、Slf4j
、java.lang.logging
,除此之外还有一些老的日志框架Log4j1.x
、Avalon LogKit
等的实现,只不过默认是禁用的。
2、配置
commons-logging
主要有两个抽象类:org.apache.commons.logging.Log
和org.apache.commons.logging.LogFactory
,其中Log
提供了统一的日志接口,而LogFactory
作为一个工厂类提供了创建Log
的方法。开发者在使用时可以手动指定一个Log
的具体实现(例如前面提到的commons-logging
提供的其他日志API的包装实现或者自己实现一个Log
),LogFactory
作为创建Log
的工厂接口,一般情况下我们不需要手动指定,除非需要使用其他高级功能。
JCL提供了三类LogFactory
的实现,Log4jApiLogFactory
、Slf4jLogFactory
和LogFactoryImpl
。默认情况下JCL将按照下面的方式选择一个LogFactory
:
- 如果Java类路径里包含
Log4j API
,并且开发者没有手动将Log4j API的实现重定向到SLF4j
,则Log4jApiLogFactory
将会被使用,JCL的日志调用将会交给Log4j API
实现。 - 如果类路径里存在
SLF4j
,则Slf4jLogFactory
将会被使用,JCL的日志调用将会交给SLF4j
实现。 - 如果都不存在,则JCL将会使用
LogFactoryImpl
。
对于LogFactoryImpl
来说,其通过下面的顺序查找Log
的实现,直到找到第一个可用的Log
时,终止查找流程:
- 查找配置属性
org.apache.commons.logging.Log
是否设置了值,开发者可以通过在Java代码里设置org.apache.commons.logging.Log
的值,或者在Java类路径下定义一个名字为commons-logging.properties
的配置文件,在配置文件里设置commons-logging.properties
的值,commons-logging.properties
文件里的配置将作为LogFactory
的属性。如果类路径下有多个配置文件的情况下,可以在配置文件里指定一个priority属性指明优先级,优先级相同的两个文件将会使用第一个找到那个。 - 查找系统配置
org.apache.commons.logging.Log
的值,如果存在这个系统属性将会使用这个属性指定的值作为Log的实现。 - 查找
java.logging
是否可用,如果可用将会使用Jdk14Logger
类作为Log
的实现。 - 如果前面几个步骤都没有找到
Log
的具体实现,将会使用默认的实现类SimpleLog
作为Log
的实现。
三、Log4j 1.x
Log4j 1.x 是Apache软件基金会开发的一个流行的Java日志框架,广泛应用于早期的Java项目中。它提供了强大的日志记录功能,支持灵活的配置和多种日志输出方式。Log4j 1.x 已经停止维护,被Log4j2.x取代。我们不不需要对其详细的做过多的了解。
Log4j 1.x使用类路径下命名为log4j.properties
的文件作为配置文件,开发者可以在该文件里配置相关属性。
我们这里重点介绍对于一些依赖Log4j1.x
的老旧项目和第三方库,我们在依赖这些项目时应该怎么处理它们的日志输出。如果我们有一个老项目project-log4j1
使用了Log4j1.x作为其日志框架,现在我们有一个新项目需要依赖project-log4j1
,但我们的新项目使用SLF4j
作为日志框架,这时候我们应该怎么处理project-log4j
的日志输出呢?对此,SLF4j
提供了适配器log4j-over-slf4j用来把调用Log4j1.x的日志操作重定向到SLF4j
的日志输出,我们只需要在项目里引入对应的依赖并提供SLF4j
的实现和配置即可。
<dependency><groupId>org.slf4j</groupId><artifactId>log4j-over-slf4j</artifactId><version>2.0.17</version>
</dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.17</version>
</dependency>
当然SLF4j
作为一个日志门面并不提供日志输出的具体实现,至于使用什么框架作为SLF4j
的具体实现对log4j-over-slf4j
无影响。
除了SLF4j
之外,apache
也提供了相应的库log4j-1.2-api用来将对Log4j1.x的调用重定向到Log4j2.x的实现,使用只需要引入依赖即可
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-1.2-api</artifactId><version>2.24.3</version>
</dependency>
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.24.3</version>
</dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.24.3</version>
</dependency>
如果使用Log4j2.x我们需要按照Log4j2.x的格式提供配置文件。
四、Log4j 2.x
1、概述
Log4j2.x是Apache Log4j1.x的升级版本,是一个支持异步日志记录的高性能日志框架,它解决了 Log4j 1.x 的许多问题,并引入了许多新特性。Log4j2.x采用接口和实现分离的设计方式,从而提高了灵活性和可扩展性,其中log4j-api
提供了抽象api,log4j-core
提供了对应的实现,开发者在使用时可以只引入log4j-api
,而使用其他例如SLF4j+Logback
日志框架作为具体实现。
通过log4j-to-slf4j可以实现把对log4j-api
的调用重定向到SLF4j
,从而实现使用log4j-api
作为门面,使用SLF4j+Logback
作为日志具体实现的需求。
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-to-slf4j</artifactId><version>2.x.x</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.36</version>
</dependency>
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.11</version>
</dependency>
此时,日志配置按照Logback的格式进行配置即可。
2、配置
Log4j2.x
提供了多种格式的配置文件,默认情况下,Log4j2.x将会按照下面的名称顺序扫描类路径找到配置文件:
log4j2-test<contextName>.<extension>
log4j2-test.<extension>
log4j2<contextName>.<extension>
log4j2.<extension>
其中contextName
表示上下文信息,一般情况下我们使用log4j.<extension>
命名的配置文件就能满足需求,extension
表示文件类型,例如log4j2.properties
Log4j2.x的配置文件支持xml
、json
、ymal
、Properties
格式,如果同时存在多个类型的配置文件,则将会按照下面的优先级查找:
- XML
- JSON
- YAML
- Properties
使用JSON格式的配置文件需要添加jackson-databind
依赖,使用yaml格式的配置文件需要添加jackson-dataformat-yaml
依赖
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.18.0</version><scope>runtime</scope>
</dependency><dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-yaml</artifactId><version>2.18.0</version><scope>runtime</scope>
</dependency>
xml类型配置文件log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="https://logging.apache.org/xml/ns"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://logging.apache.org/xml/nshttps://logging.apache.org/xml/ns/log4j-config-2.xsd"><Appenders><Console name="CONSOLE"><PatternLayout pattern="%p - %m%n"/></Console><File name="MAIN" fileName="logs/main.log"><JsonTemplateLayout/></File><File name="DEBUG_LOG" fileName="logs/debug.log"><PatternLayout pattern="%d [%t] %p %c - %m%n"/></File></Appenders><Loggers><Root level="INFO"><AppenderRef ref="CONSOLE" level="WARN"/><AppenderRef ref="MAIN"/></Root><Logger name="org.example" level="DEBUG"><AppenderRef ref="DEBUG_LOG"/></Logger></Loggers>
</Configuration>
json格式配置文件log4j2.json
{"Configuration": {"Appenders": {"Console": {"name": "CONSOLE","PatternLayout": {"pattern": "%p - %m%n"}},"File": [{"name": "MAIN","fileName": "logs/main.log","JsonTemplateLayout": {}},{"name": "DEBUG_LOG","fileName": "logs/debug.log","PatternLayout": {"pattern": "%d [%t] %p %c - %m%n"}}]},"Loggers": {"Root": {"level": "INFO","AppenderRef": [{"ref": "CONSOLE","level": "WARN"},{"ref": "MAIN"}]},"Logger": {"name": "org.example","level": "DEBUG","AppenderRef": {"ref": "DEBUG_LOG"}}}}
}
ymal格式配置文件log4j2.yaml
Configuration:Appenders:Console:name: "CONSOLE"PatternLayout:pattern: "%p - %m%n"File:- name: "MAIN"fileName: "logs/main.log"JsonTemplateLayout: {}- name: "DEBUG_LOG"fileName: "logs/debug.log"PatternLayout:pattern: "%d [%t] %p %c - %m%n"Loggers:Root:level: "INFO"AppenderRef:- ref: "CONSOLE"level: "WARN"- ref: "MAIN"Logger:name: "org.example"level: "DEBUG"AppenderRef:ref: "DEBUG_LOG"
Properties格式配置文件log4j2.properties
appender.0.type = Console
appender.0.name = CONSOLE
appender.0.layout.type = PatternLayout
appender.0.layout.pattern = %p - %m%nappender.1.type = File
appender.1.name = MAIN
appender.1.fileName = logs/main.log
appender.1.layout.type = JsonTemplateLayoutappender.2.type = File
appender.2.name = DEBUG_LOG
appender.2.fileName = logs/debug.log
appender.2.layout.type = PatternLayout
appender.2.layout.pattern = %d [%t] %p %c - %m%nrootLogger.level = INFO
rootLogger.appenderRef.0.ref = CONSOLE
rootLogger.appenderRef.0.level = WARN
rootLogger.appenderRef.1.ref = MAINlogger.0.name = org.example
logger.0.level = DEBUG
logger.0.appenderRef.0.ref = DEBUG_LOG
五、Slf4j
1、概述
Slf4j
是一个日志门面(Facade),只提供了日志接口抽象,使用Slf4j
需要引入具体的日志实现,一般情况下使用Logback
作为Slf4j
的实现,因为Logback
就是SLF4j
api的标准实现。
使用SLF4j+Logback作为日志框架需要引入如下依赖:
<dependency> <groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.17</version>
</dependency><!-- JAVAX EE -->
<dependency> <groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.3.14</version>
</dependency><!-- Jakarta EE -->
<dependency> <groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.5.15</version>
</dependency>
Logback提供了logback-core
模块实现了基础的日志功能,logback-classic
在logback-core
的基础上实现了SLF4j
API,在配合SLF4j
使用时,一般情况下我们只需引入logback-classic
即可。
除了Logback外,开发者也可以使用其他日志框架作为SLF4j
的实现,例如Log4j2.x
。apache提供了log4j-slf4j2-impl用来把SLF4j的API调用重定向到Log4j2.x。
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j2-impl</artifactId><version>2.24.3</version><scope>test</scope>
</dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.x.x</version>
</dependency>
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.x.x</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.36</version>
</dependency>
把SLF4j
桥接到Log4j2.x
后,配置文件将使用相应的Log4j2.x
配置文件。
也可以使用slf4j-log4j12
将SLF4j
重定向到Log4j1.x,使用slf4j-jdk14
将SLF4j
重定向到java.util.logging
,不过正常情况下不这样使用,现在项目中使用最多的就是SLF4j+Logback
的搭配方式。
2、配置
LogBack使用XML作为配置文件的格式,默认情况下Logback将会在类路径下按顺序查找命名为logback-test.xml
或logback.xml
的配置文件
logback.xml
<configuration><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><!-- encoders are assigned the typech.qos.logback.classic.encoder.PatternLayoutEncoder by default --><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n</pattern></encoder></appender><root level="debug"><appender-ref ref="STDOUT" /></root>
</configuration>
六、其他框架
除了上面几个常用的日志框架以外,Java还有很多其他的日志框架,这里只介绍在实际项目中比较常见的几种。