Java常用日志框架介绍

Java提供了很多第三方的日志框架可供使用,按照现在的设计理念,一般把日志框架分成门面(Facade)部分和具体实现(Implementation)部分,门面(Facade)提供了抽象的api规范,实现(Implementation)负责实现api完成具体的日志记录功能。开发者在使用日志框架时使用的是门面提供的api,可以根据实际情况灵活的选择不同的api实现。

一、java.util.logging

1、概述

java.util.logging是Java标准库自带的日志框架,使用时无需引入第三方依赖,提供的功能相对简单,一般不在实际项目中使用。

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指定:

she 复制代码
java -Djava.util.logging.config.file=path/logging.properties mainApp.jar

使用代码指定:

java 复制代码
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.");
    }
}

配置文件内容:

properties 复制代码
# 全局日志级别
.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.xSlf4jjava.lang.logging,除此之外还有一些老的日志框架Log4j1.xAvalon LogKit等的实现,只不过默认是禁用的。

2、配置

commons-logging主要有两个抽象类:org.apache.commons.logging.Logorg.apache.commons.logging.LogFactory,其中Log提供了统一的日志接口,而LogFactory作为一个工厂类提供了创建Log的方法。开发者在使用时可以手动指定一个Log的具体实现(例如前面提到的commons-logging提供的其他日志API的包装实现或者自己实现一个Log),LogFactory作为创建Log的工厂接口,一般情况下我们不需要手动指定,除非需要使用其他高级功能。

JCL提供了三类LogFactory的实现,Log4jApiLogFactorySlf4jLogFactoryLogFactoryImpl。默认情况下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的实现和配置即可。

xml 复制代码
<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的实现,使用只需要引入依赖即可

xml 复制代码
<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作为日志具体实现的需求。

xml 复制代码
<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将会按照下面的名称顺序扫描类路径找到配置文件:

  1. log4j2-test<contextName>.<extension>
  2. log4j2-test.<extension>
  3. log4j2<contextName>.<extension>
  4. log4j2.<extension>

其中contextName表示上下文信息,一般情况下我们使用log4j.<extension>命名的配置文件就能满足需求,extension表示文件类型,例如log4j2.properties

Log4j2.x的配置文件支持xmljsonymalProperties格式,如果同时存在多个类型的配置文件,则将会按照下面的优先级查找:

  1. XML
  2. JSON
  3. YAML
  4. Properties

使用JSON格式的配置文件需要添加jackson-databind依赖,使用yaml格式的配置文件需要添加jackson-dataformat-yaml依赖

xml 复制代码
<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 复制代码
<?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/ns
                   https://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

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

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

properties 复制代码
appender.0.type = Console
appender.0.name = CONSOLE
appender.0.layout.type = PatternLayout
appender.0.layout.pattern = %p - %m%n

appender.1.type = File
appender.1.name = MAIN
appender.1.fileName = logs/main.log
appender.1.layout.type = JsonTemplateLayout

appender.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%n

rootLogger.level = INFO
rootLogger.appenderRef.0.ref = CONSOLE
rootLogger.appenderRef.0.level = WARN
rootLogger.appenderRef.1.ref = MAIN

logger.0.name = org.example
logger.0.level = DEBUG
logger.0.appenderRef.0.ref = DEBUG_LOG

五、Slf4j

1、概述

Slf4j是一个日志门面(Facade),只提供了日志接口抽象,使用Slf4j需要引入具体的日志实现,一般情况下使用Logback作为Slf4j的实现,因为Logback就是SLF4japi的标准实现。

使用SLF4j+Logback作为日志框架需要引入如下依赖:

xml 复制代码
<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-classiclogback-core的基础上实现了SLF4jAPI,在配合SLF4j使用时,一般情况下我们只需引入logback-classic即可。

除了Logback外,开发者也可以使用其他日志框架作为SLF4j的实现,例如Log4j2.x。apache提供了log4j-slf4j2-impl用来把SLF4j的API调用重定向到Log4j2.x。

xml 复制代码
<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-log4j12SLF4j重定向到Log4j1.x,使用slf4j-jdk14SLF4j重定向到java.util.logging,不过正常情况下不这样使用,现在项目中使用最多的就是SLF4j+Logback的搭配方式。

2、配置

LogBack使用XML作为配置文件的格式,默认情况下Logback将会在类路径下按顺序查找命名为logback-test.xmllogback.xml的配置文件

logback.xml

xml 复制代码
<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.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还有很多其他的日志框架,这里只介绍在实际项目中比较常见的几种。

相关推荐
Seven972 分钟前
剑指offer-17、树的⼦结构
java
我今晚不熬夜18 分钟前
JSON在java中的使用
java·开发语言·json
Code季风1 小时前
Spring 异常处理最佳实践:从基础配置到生产级应用
java·spring boot·spring
回家路上绕了弯1 小时前
Java 堆深度解析:内存管理的核心战场
java·jvm
Code季风1 小时前
Spring IoC 容器性能提升指南:启动速度与运行效率优化策略
java·spring·性能优化
谦行1 小时前
前端视角 Java Web 入门手册 5.10:真实世界 Web 开发—— 单元测试
java·spring boot·后端
hhua01231 小时前
理解“无界队列”与“有界队列”及其适用场景
java·队列
LZQqqqqo1 小时前
C# 接口(interface 定义接口的关键字)
java·开发语言·c#
寒水馨2 小时前
Java 9 新特性解析
java·开发语言·新特性·java9·jdk9
SimonKing2 小时前
甩掉手动赋值!MyBatis-Plus 自动填充实战秘籍
java·后端·程序员