如果你曾经不得不分析生产中的问题,我相信你知道良好的日志记录是多么重要。良好的日志记录需要三件事:

  1. 日志消息需要提供所需的信息,以了解应用程序在内部执行的操作。
  2. 编写日志消息必须尽可能高效,这样才不会影响应用程序的性能。
  3. 您需要能够根据不同的部署环境和情况调整日志详细信息。

虽然您仍然需要自己决定应该为每个用例编写哪些日志消息,但您不需要担心需求2和需求3。各种日志框架已经解决了这些技术要求。您只需要选择其中一个,并使用它来编写日志消息。

为了让它变得更好,SLF4J提供了一个标准化的API,其中大多数框架都以某种方式实现了该API。这使您能够在不更改代码的情况下更改日志框架。只需将依赖关系更改为实现SLF4J接口的不同框架。

使用SLF4J编写日志消息

使用SLF4J编写日志消息非常简单。首先需要调用LoggerFactory上的getLogger方法来实例化一个新的Logger对象。然后,您可以调用记录器上的debuginfowarningerrorfatal方法之一,以编写具有相应日志级别的日志消息。这里你可以看到一个典型的例子:

public class MyClass { 
    Logger log = LoggerFactory.getLogger(this.getClass().getName());
 
    public void myMethod() { 
        log.info("This is an info message"); 
        // ... 
    } 
}

那么,如果这些框架很容易互换,你应该选择哪一个呢?

这个问题的答案并不像你想象的那么简单。Java世界中广泛使用了几种可用的框架。在本文中,我想向您介绍Log4j及其两个继任者LogbackLog4j2

Apache Log4J

Apache Log4J是一个非常古老的日志框架,多年来一直是最流行的日志框架。它介绍了一些基本概念,如分层日志级别和日志记录器,这些概念仍然被现代日志框架使用。

开发团队在2015年宣布了Log4j的生命终结。虽然很多遗留项目仍在使用它,但如果您启动一个新项目,您应该更喜欢本文中讨论的其他框架之一。

在我们讨论Logback和Log4j2之前,让我们先快速了解一下所需的依赖项和配置。

必需的依赖项

如果想在应用程序中使用Log4j,需要添加Log4j.jar文件到你的类路径。您可以在下面的代码片段中看到所需的Maven依赖项。

<dependency> 
    <groupId>log4j</groupId> 
    <artifactId>log4j</artifactId> 
    <version>1.2.17</version> 
</dependency>

Log4j本机不支持SLF4J。您还需要添加以下依赖项,以便能够通过标准化接口使用Log4j。

<dependency> 
    <groupId>org.slf4j</groupId> 
    <artifactId>slf4j-log4j12</artifactId> 
    <scope>test</scope> 
</dependency>

配置Log4j

除了log4j.jar文件,您需要在log4j中定义appender和logger的日志级别。appender将日志消息写入目标,例如文件或数据库。logger和level定义写入日志文件的日志消息的粒度。

下面的代码片段显示了一个应用程序开发系统的典型log4j.properties,该应用程序使用Hibernate作为对象关系映射器。它会将所有日志消息写入文件应用程序。记录并将常规日志级别设置为INFO。该配置还设置记录器组织的日志级别。org.hibernate.type.descriptor.sql要跟踪的sql到TRACE。这是Hibernate的两个记录器,它们将执行的SQL语句及其绑定参数值写入配置的文件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{HH:mm:ss,SSS} %-5p [%c] - %m%n 

log4j.rootLogger=info, file 
# basic log level for all messages 
log4j.logger.org.hibernate=info 

# SQL statements and parameters 
log4j.logger.org.hibernate.SQL=debug 
log4j.logger.org.hibernate.type.descriptor.sql=trace

基于此配置,您可以使用SLF4J API编写日志消息。这就是Log4j的全部内容。

Logback

Logback由实现Log4j的开发人员编写,其目标是成为其继任者。它遵循与Log4j相同的概念,但被重写是为了提高性能、本机支持SLF4J,以及实现其他一些改进,如高级过滤选项和自动重新加载日志配置。

该框架由三部分组成:

  1. logback-core
  2. logback-classic
  3. logback-access

Logback core提供了日志框架的核心功能。Logback classic为核心功能添加了更多功能,例如对SLF4J的本机支持。logback access将其与servlet容器集成,以便您可以使用它编写HTTP访问日志。

必需的依赖项

您只需要定义对logback classic的依赖。它包括对logback core和SLF4J API的依赖关系。

<dependency> 
    <groupId>ch.qos.logback</groupId> 
    <artifactId>logback-classic</artifactId> 
    <version>1.2.3</version> 
</dependency>

配置Logback

Logback不需要任何配置。默认情况下,它会将调试级别或更高级别的所有日志消息写入标准输出。您可以使用XML或Groovy格式的自定义配置文件来更改这一点。

Logback使用与Log4j相同的概念。因此,即使它们使用不同的文件格式,它们的配置也非常相似,这并不奇怪。下面的代码片段显示的配置与我在Log4j中使用的配置相同。

<configuration> 
    <appender name="FILE" class="ch.qos.logback.core.FileAppender"> 
        <file>app.log</file> 
        <encoder> 
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern> 
        </encoder> 
    </appender> 
    <logger name="org.hibernate.SQL" level="DEBUG" /> 
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" /> 
    <root level="info"> 
        <appender-ref ref="FILE" /> 
    </root> 
</configuration>

在添加了所需的依赖项并配置了Logback之后,可以使用它通过SLF4J API编写日志消息。因此,如果您想从Logback提供的改进中获益,您不需要更改任何代码来用Logback替换Log4j。

现在让我们看看Log4j2。

Apache Log4j2

Apache Log4j2是这三个框架中最年轻的一个,其目标是通过提供自己对Log4j的改进来改进这两个框架,包括Logback中包含的一些改进,并避免Log4j和Logback的问题。

因此,与Logback一样,Log4j2支持SLF4J,自动重新加载日志配置,并支持高级过滤选项。除了这些特性之外,它还允许基于lambda表达式对日志语句进行延迟计算,为低延迟系统提供异步记录器,并提供无垃圾模式以避免垃圾收集器操作造成的任何延迟。

所有这些特性使Log4j2成为这三种日志框架中最先进、最快的。

必需的依赖项

Log4j2将其API和实现打包在两个单独的jar文件中。可以使用log4japi实现和构建应用程序。您需要提供额外的log4j内核。运行时使用jar。如果要使用SLF4JAPI,还需要log4j-slf4j-impl.jar文件,其中包含两个API之间的桥梁。

<dependency> 
    <groupId>org.apache.logging.log4j</groupId> 
    <artifactId>log4j-api</artifactId> 
    <version>2.11.1</version> 
</dependency> 
<dependency> 
    <groupId>org.apache.logging.log4j</groupId> 
    <artifactId>log4j-core</artifactId> 
    <version>2.11.1</version> 
    </dependency> 
<dependency> 
    <groupId>org.apache.logging.log4j</groupId> 
    <artifactId>log4j-slf4j-impl</artifactId> 
    <version>2.11.1</version> 
</dependency>

配置Log4j2

Log4j2的配置遵循与前面两个日志框架相同的原则,因此看起来非常相似。

<Configuration status="info"> 
    <Appenders> 
        <File name="FILE" fileName="app.log"> 
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> 
        </File> 
    </Appenders> 
    <Loggers> 
        <Logger name="org.hibernate.SQL" level="DEBUG"> 
            <AppenderRef ref="FILE"/> 
        </Logger> 
        <Logger name="org.hibernate.type.descriptor.sql" level="TRACE"> 
            <AppenderRef ref="FILE"/> 
        </Logger> 
        <Root level="info"> 
            <AppenderRef ref="FILE"/> 
        </Root> 
    </Loggers> 
</Configuration>

结论

Log4j、Logback和Log4j2是广泛使用的良好日志框架。那么你应该用哪一个呢?

我建议使用Log4j2,因为它是三种框架中最快、最先进的。如果性能不是您的最高优先级,那么Logback仍然是一个不错的选择。