使用Log4j2进行日志记录:Java开发者指南

软件开发过程中最关键的部分之一是拥有适当的日志记录。有许多不同的Java日志框架可供选择,选择一个易于使用的框架非常重要。与此同时,您选择的框架应具有高性能、可扩展的功能并允许自定义。Log4j2是一个免费的Java日志库,它满足所有这些要求。

将Log4j2集成到任何应用程序中可以解锁高级过滤、Java 8 lambda支持、属性查找和自定义日志级别等选项。让我们看看如何将Log4j2添加到您的项目中以及哪些功能可以帮助您保持在顶峰状态。

Log4j2是什么?

日志记录是捕获有用信息(称为日志)以供以后引用和分析的方法。您可以使用这些日志快速查找应用程序代码中的问题。应用程序日志有助于理解代码流程并解决生产问题和错误。

除了诊断用例外,日志还用于审计目的,例如跟踪邮件是否已成功发送给用户。

Log4j2是最受欢迎的Java日志库之一。它是非常有影响力的Log4j库的继任者。Log4j2由Apache软件基金会开发,是Apache Logging Services的一部分,是一款自由开源软件(FOSS),根据Apache许可证2.0版本分发。

Log4j2建立在原始Log4j的坚实基础之上。使用Logger而不是简单的打印语句System.out.println()有很多优势。这包括对显示哪些消息和避免其他日志消息的控制。在没有调试器的生产环境中,拥有适当的日志记录是至关重要的。

如何将Log4j2添加到您的项目中?

有几种方法可以将Log4j2添加到您的Java项目中。建议使用Java 8或更高版本以使用Log4j2的所有功能。

让我们根据您可能具有的要求讨论一下可以通过哪些方法添加Log4j2。

使用Apache Maven将Log4j2添加到项目

如果您的项目使用Apache Maven作为构建系统,则需要将Log4j2依赖项添加到pom.xml文件中。


  
    org.apache.logging.log4j
    log4j-api
    2.20.0
  
  
    org.apache.logging.log4j
    log4j-core
    2.20.0
  

为了使在不同的工件之间维护相同的版本更容易,Log4j2有一个Bill of Material (BOM) pom.xml文件。如果您将其添加到依赖管理中,您就不必逐个添加版本。



  
    
      org.apache.logging.log4j
      log4j-bom
      2.20.0
      import
      pom
    
  




  
    org.apache.logging.log4j
    log4j-api
  
  
    org.apache.logging.log4j
    log4j-core
  

使用Apache Gradle将Log4j2添加到项目

如果您使用Apache Gradle作为构建工具,可以将Log4j2依赖项添加到build.gradle文件中。

依赖项 {
implementation ‘org.apache.logging.log4j:log4j-api:2.20.0'
implementation ‘org.apache.logging.log4j:log4j-core:2.20.0'
}

如果您使用的是Gradle 5.0或更高版本,则可以选择导入Log4j2 Maven Bill Of Materials (BOM)以保持一致的依赖版本。可以通过将以下内容添加到您的 build.gradle 文件来实现。

依赖项 {
implementation platform(‘org.apache.logging.log4j:log4j-bom:2.20.0')

implementation ‘org.apache.logging.log4j:log4j-api'
runtimeOnly ‘org.apache.logging.log4j:log4j-core'
}

对于Gradle版本2.8-4.10,没有直接导入Maven BOM的选项。您需要为依赖管理功能添加一个额外的插件。

插件 {
id ‘io.spring.dependency-management' version ‘1.0.15.RELEASE'
}

dependencyManagement {
imports {
mavenBom ‘org.apache.logging.log4j:log4j-bom:2.20.0'
}
}

依赖项 {
implementation ‘org.apache.logging.log4j:log4j-api'
runtimeOnly ‘org.apache.logging.log4j:log4j-core'
}

将Log4j2添加到没有构建工具的独立应用程序中

如果您的项目没有构建工具,则可以从官方链接下载所需版本的Log4j2。下载后,需要确保应用程序的类路径包含以下jar文件。

log4j-api-2.20.0.jar
log4j-core-2.20.0.jar

Log4j2中的组件是什么?

为了充分理解Log4j2的功能并利用其能力,了解Log4j2的工作原理是很重要的。在表面下,Log4j2由几个构建块组成。让我们逐一讨论它们。

#1. LoggerContext

LoggerContext是日志系统的中心单元。它保存应用程序中请求的所有Loggers。它还保存对配置的引用。

#2. Configuration

Configuration包含日志系统所需的所有信息。这包括Loggers、Appenders、Filters等。在Log4j2中,您可以使用各种文件格式(如XML、JSON和YAML)或通过Log4j2 API以编程方式定义配置。

每当配置中的任何属性更改时,自动重新加载将发生。因此,无需重新启动应用程序。

#3. Logger

Log4j2系统的主要组件是Logger。在应用程序代码中使用LogManager.getLogger()语句获取日志记录器,并用于生成日志。可以以调试、信息、警告、错误和致命等各种严重级别生成日志消息。

#4. LoggerConfig

LoggerConfig负责特定Logger的行为。它定义了由该特定记录器生成的日志事件的行为和设置。它允许配置不同的日志级别、设置附加器和应用过滤器。

#5. Filter

您可以使用Log4j2中的过滤器对日志事件进行选择性处理。过滤器基于特定条件应用。您可以将这些过滤器应用于记录器或追加器。过滤器控制允许通过日志管道进行进一步处理的日志事件。借助过滤器的帮助,可以对日志行为进行微调,确保只处理相关日志。

#6. 追加器

任何日志消息的目标由追加器确定。单个记录器可以有多个追加器。给定记录器的日志事件将发送到所有追加器。Log4j2有很多预配置的追加器。例如,ConsoleAppender用于将消息记录到控制台,而FileAppender用于将消息输出到文件。每个追加器都需要自己的布局,确定最终日志消息的样式。

#7.布局

在Log4j2中,布局用于定义最终日志消息的样式。布局与追加器相关联。追加器确定输出目标,而布局描述消息的输出方式。

Log4j2的五个顶级特性

Log4j2功能丰富,这使其与其他可用的Java日志框架有所区别。从具有异步记录器到支持Java 8 lambda表达式,Log4j2具有优势。让我们讨论一些该框架的显着特点。

#1.通过插件扩展功能

在Log4j 1.x中,为了创建扩展,需要进行大量代码修改。Log4j2通过引入插件系统解决了可扩展性问题。

您可以在类上使用@Plugin注释声明一个新插件。通过使用插件的功能,可以创建自己的组件,如过滤器和追加器。第三方组件也可以轻松添加到库中。

#2.支持Java 8 Lambda表达式

在Log4j2版本2.4发布时,引入了对Java 8 lambda表达式的支持。使用lambda表达式,可以内联定义日志逻辑。这减少了对多行检查或匿名内部类的需求。这还确保不会不必要地执行昂贵的方法。因此,代码不仅更清晰易读,而且系统开销也减少。

让我们考虑一个例子,您记录一个昂贵操作的结果,但仅在启用了调试级别时才记录。在支持lambda之前,可以使用以下代码执行此操作:

if (logger.isDebugEnabled()) {
    logger.debug("The output of the given operation is: {}", expensiveOperation());
}

有多个这样的用例不必要地引入了条件检查。然而,使用Log42,可以执行相同的操作如下:

logger.debug("The output of the given operation is: {}", () -> expensiveOperation()

只有在启用了调试级别时,才会计算方法exprensiveOperation()。不需要任何显式检查。

#3. 异步记录器

每个日志事件都是一个I/O操作,这会增加系统开销。为了减轻这个问题,Log4j2引入了异步记录器,它在一个单独的线程中运行,而不是在应用程序线程中运行。当使用异步记录器时,调用者线程在调用logger.log()方法后立即恢复控制权。

这使得它可以继续应用程序逻辑,而不是等待日志事件完成。利用这种异步行为可以实现更大的日志吞吐量。您可以选择默认情况下将所有记录器都设置为异步或者同时使用同步和异步行为。

#4. 无垃圾日志记录

在Java中,垃圾收集是自动清除应用程序中未使用的对象的过程。虽然您不必手动处理此操作,但垃圾收集确实会有自己的开销。

如果您的应用程序在短时间内创建了过多的对象,垃圾收集过程可能会占用比必要更多的系统资源。包括Log4j的以前版本在内的几个日志记录库在日志记录过程中创建了许多临时对象。随后,对垃圾收集器的压力增加会影响系统的性能。

从2.6版本开始,Log4j2以“无垃圾”模式运行。这是默认行为。因此,对象被重复使用,临时对象的创建大大减少。

以下图片展示了Log4j2版本2.6相对于Log4j2版本2.5如何减少不必要对象的问题。

在Log4j2版本2.5中,日志记录过程中创建了许多临时对象;来源:apache.org
在Log4j2.6中,日志记录过程中没有创建临时对象;来源:apache.org

#5. 查找

在log4j2中,您可以使用查找将上下文信息添加到日志中。通过利用它们,您可以从各种来源(如系统属性、环境变量或自定义定义的值)中添加数据。因此,您可以包含动态获取的相关信息,使日志更有用。

让我们考虑一个例子,您想要在所有日志行中记录用户的会话ID。这将允许您搜索与会话ID对应的所有日志。

这样做的蛮力方法是逐个显式添加会话ID,这变得难以维护。很快您可能会忘记添加它,从而丢失宝贵的信息。

logger.info("The user data has been fetched for session id {}", sessionId);
...
logger.info("The transaction has been processed for session id {}", sessionId);
...
logger.info("Request has been successfully processed for session id {}", sessionId);

更好的方法是使用上下文映射查找器。会话ID可以在应用程序代码中添加到线程上下文中。然后可以在Log4j2配置中使用该值。因此,不需要在日志消息中显式提到它。

ThreadContext.put("sessionId", sessionId);

一旦添加了该值,可以在查找中使用关键字ctx


  
    %d %p %c{1.} [%t] $${ctx:sessionId} %m%n
  

如何在Log4j2中创建自定义日志级别?

Log4j2中的日志级别用于根据其严重程度或重要性对日志事件进行分类。您可以在应用程序代码中记录消息时控制日志级别。

例如,logger.debug()添加了DEBUG级别。相应地,logger.error()添加了ERROR级别。这确定了最终显示在输出中的消息。您可以在配置文件中配置日志级别。

Log4j2中预配置的日志级别及其对应的值如下所示。

OFF 0
FATAL 100
ERROR 200
WARN 300
INFO 400
DEBUG 500
TRACE 600
ALL 最大值

如果将日志级别设置为特定级别,则将输出该对应值及其上方(值较小)的所有日志行。其他日志行将被忽略。

例如,如果将日志级别设置为WARN,则将显示WARN、ERROR和FATAL消息。具有不同级别的任何日志行都将被忽略。当您在不同的环境中运行相同的代码时,这是非常有用的。

在开发环境中运行代码时,您可能希望将日志级别设置为INFO或DEBUG。这将允许您查看更多的日志,并有助于开发过程。然而,在生产环境中运行时,您希望将其设置为ERROR。这样,您将能够专注于查找任何异常发生的问题,而无需浏览不必要的日志行。

有时您可能希望在预配置的日志级别之外添加自定义日志级别。Log4j2允许您轻松实现此目的。让我们看看如何添加自定义日志级别并在应用程序中使用它们。

1. 通过配置文件添加自定义日志级别
您可以通过在配置文件中声明它们来添加自定义日志级别。

在下面的示例中,已定义了一个名为NOTICE的自定义日志级别,其值为450。这将使它位于INFO(值为400)和DEBUG(值为500)之间。这意味着如果级别设置为NOTICE,则会记录INFO消息,但会跳过DEBUG消息。

2. 在代码中添加自定义日志级别
除了在配置文件中声明它们外,您还可以在代码中定义自己的自定义日志级别。

这将创建一个名为VERBOSE的新日志级别。此日志级别将位于DEBUG(值为500)和TRACE(值为600)之间。如果记录器设置为VERBOSE级别,则将记录VERBOSE及以上的所有日志消息,包括DEBUG。但是,将跳过TRACE消息。

3. 在代码中使用自定义日志级别
在使用自定义日志级别之前,首先需要声明它们。您可以在配置文件或代码中声明它们。一旦声明,您可以自由使用它们。

这个代码示例展示了如何声明一个自定义级别NOTICE,并且如何使用它。

final Level NOTICE = Level.forName("NOTICE", 550);

final Logger logger = LogManager.getLogger();
logger.log(NOTICE, "一个注意级别的消息");

虽然这样生成了所需的具有新创建级别的消息,但总是显式地传递级别可能变得繁琐。幸运的是,您可以生成源代码,以便获得用于记录自定义级别的帮助方法。使用这些方法,您可以使用自己的logger.notice()方法,就像使用logger.debug()logger.error()一样。

Log4j2附带了一个实用程序,帮助您创建自己的扩展记录器。以下命令创建一个名为CustomLogger.java的Java文件。该文件包含现有的日志方法,以及对NOTICE级别生成的新方法。

java -cp log4j-core-2.20.0.jar org.apache.logging.log4j.core.tools.ExtendedLoggerGenerator 
        com.example.CustomLogger NOTICE=450 > com/example/CustomLogger.java

生成文件后,您可以在代码中使用这个类来创建新的记录器。这些记录器将包含您自定义日志级别的附加方法。因此,您可以扩展记录器的功能。

final Logger logger = CustomLogger.create(ValueFirstSmsSender.class);

//这个新方法类似于使用logger.debug()
logger.notice("一个注意级别的消息");

结论

Log4j2是一个非常强大的Java日志框架,提供了各种功能、配置、性能改进等。日志是软件开发过程中非常重要的一部分,拥有像Log4j2这样健壮的框架可以增强应用程序的能力。

Log4j2的灵活性和可扩展性允许适当地捕获应用程序中发生的事件。随后,它使您能够将日志视为强大的调试和审计工具。凭借其所有的功能和改进,Log4j2在各种软件项目中脱颖而出,成为首选。

您可能还对这些感兴趣:Java IDEs and online compliers

类似文章