LOG4J2 配置:具体入门指南

埃里克·迪特里希

2018 年 9 月 5 日

软件开发中最烦人的方面之一相对是日志记录。如果一个非平庸的应用程序短少日志记录,那么保护它的人都会遇到困难,预先调试将次要是一个猜谜游戏。明天,咱们通过提供无关 log4j2 配置的教程,为解决这种状况做出了另一奉献。

有很多办法能够为Java记录日志。您能够应用更手动的办法,但举荐的办法是采纳专用的日志记录框架。这就是为什么咱们要介绍 Apache log4j2,它是 log4j 的改良版本,是行业标准的日志框架之一。

咱们将首先疾速回顾一下咱们之前对于 Java 日志的文章,并介绍一些对于 log4j2 的事实。而后咱们将持续介绍咱们在上一个教程中开始编写的示例应用程序的状态。

之后,咱们进入文章的重点。您将学习如何配置 log4j2,从根底开始,并逐渐学习更高级的主题,例如日志格局、附加程序、日志级别和日志层次结构。

让咱们开始吧。

应用 Log4j2 进行日志记录:又不是头一回了

本教程中,咱们应用了 log4j 版本 2,这是来自 Apache 我的项目的日志框架。

让咱们进一步理解 Java 应用程序日志并查看 log4j2 配置。明天咱们将介绍 log4j2 配置的根本方面,以帮忙您入门。

Log4j 的性能使其成为 Java 最风行的日志框架之一。它能够配置为多个日志记录目的地和各种日志文件格式。

能够在单个类级别过滤和定向日志音讯,从而使开发人员和运维人员可能对应用程序音讯进行精密管制。

让咱们通过应用命令行 Java 应用程序配置 log4j 来查看这些机制。

示例应用程序

让咱们应用 log4j 进行日志记录的应用程序。

package com.company;import org.apache.logging.log4j.Logger;import org.apache.logging.log4j.LogManager;public class Main {  private static final Logger logger = LogManager.getLogger(Main.class);  public static void main(String[] args) {      String message = "Hello there!";      logger.trace(message);      logger.debug(message);      logger.info(message);      logger.warn(message);      logger.error(message);      logger.fatal(message);  }}

咱们在每个 log4j 预约义的日志级别记录雷同的音讯:跟踪、调试、信息、正告、谬误和致命。

咱们将应用 log4j 的 YAML 文件格式,因而您须要向pom.xml(或build.gradle)增加一些额定的依赖项。

<dependencies>    <dependency>        <groupId>org.apache.logging.log4j</groupId>        <artifactId>log4j-api</artifactId>        <version>2.12.1</version>    </dependency>    <dependency>        <groupId>org.apache.logging.log4j</groupId>        <artifactId>log4j-core</artifactId>        <version>2.12.1</version>    </dependency>    <dependency>        <groupId>com.fasterxml.jackson.dataformat</groupId>        <artifactId>jackson-dataformat-yaml</artifactId>        <version>2.10.0</version>    </dependency>    <dependency>        <groupId>com.fasterxml.jackson.core</groupId>        <artifactId>jackson-databind</artifactId>        <version>2.10.0</version>    </dependency></dependencies>

设置此代码,以便您能够应用您喜爱的 Java 工具构建和运行它。

根本的 Log4j2 配置

默认配置

让咱们在没有 log4j 配置文件的状况下运行咱们的应用程序。如果您曾经有一个,请将其删除或将其挪动到另一个文件名,以便 log4j 将疏忽它。

当咱们运行应用程序时,咱们会在管制台上看到:

09:38:14.114 [main] ERROR com.company.Main - Hello there!09:38:14.119 [main] FATAL com.company.Main - Hello there!

六个日志音讯中的两个,指定为“谬误”和“致命”的音讯被发送到控制台。

Log4j 有一个默认配置。它将记录到控制台,显示归类为“谬误”或更高级别的音讯。

理解 log4j 在没有配置文件的状况下如何运行很有用,但让咱们看看如何依据咱们的须要设置它。

配置文件地位

咱们能够通过log4j.configurationFile零碎属性在特定地位为 log4j 提供配置文件。这是它将查找配置文件的第一个地位。

如果 log4j 找不到零碎属性,它会在类门路中查找文件。因为 log4j 版本 2 反对四种不同的文件格式和两种不同的文件命名约定,因而定位文件的规定很简单。在咱们介绍了不同的选项后,咱们将探讨它们。

配置文件格式

Log4j 将加载 Java 属性和 YAML、JSON 和 XML 配置文件。它通过查看文件扩展名来辨认文件格式。

  • Java properties — .properties
  • YAML — .yaml or .yml
  • JSON — .json or .jsn
  • XML — .xml

log4j.configurationFile 零碎属性指定的文件必须具备这些文件扩展名之一,但能够具备任何根本名称。Log4j 将依据扩展名批示的格局对其进行解析。

当 log4j 扫描文件的类门路时,它会依照下面列出的程序扫描每种格局,并在找到匹配项时进行。

例如,如果它找到一个 YAML 配置,它将进行搜寻并加载它。如果没有 YAML 文件但它找到了 JSON,它将进行搜寻并应用它。

配置文件名

当 log4j 扫描类门路时,它会查找两个文件名之一:log4j2-test.[extension] 或 log4j2.[extension]。

它首先加载测试文件,为开发人员提供了一种不便的机制,能够在不扭转标准配置的状况下强制应用程序在调试或跟踪级别进行记录。

扫描配置

当咱们将文件格式和名称的规定放在一起时,咱们能够看到log4j的自我配置算法。

如果以下任何步骤胜利,log4j 将进行并加载生成的配置文件。

  1. 查看 log4j.configurationFile零碎属性并在找到时加载指定的文件。
  2. 在类门路中搜寻 log4j2-test.properties。
  3. 扫描 log4j2-test.yaml 或 log4j2-test.yml 的类门路
  4. 查看 log4j2-test.json 或 log4j2-test.jsn
  5. 搜寻 log4j2-test.xml
  6. 寻找 log4j2.properties
  7. 搜寻 log4j2.yaml 或 log4j2.yml
  8. 扫描 log4j2.json 或 log4j2.jsn 的类门路
  9. 查看 log4j2.xml
  10. 应用默认配置。

实际正确的配置文件卫生

log4j 有 12 个潜在的配置文件名。如果应用程序在生产环境中记录了不必要的音讯,则加载谬误的信息可能会导致日志信息失落或性能降落。

在部署代码之前,请确保您的应用程序只有一个配置文件,并且您晓得它在哪里。如果您保持从类门路加载配置,请在公布代码之前扫描虚伪文件。

根本配置

当初咱们晓得如何为 log4j 提供配置,让咱们创立一个并应用它来自定义咱们的应用程序。

从新扫视 Log4j 的默认配置

让咱们从默认配置开始,而后从那里批改咱们应用程序的行为。咱们将从 log4j 的配置规定中获取提醒并应用 YAML。

默认配置如下所示:

Configuration:  status: warn  Appenders:    Console:      name: Console      target: SYSTEM_OUT      PatternLayout:        Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"  Loggers:    Root:      level: error      AppenderRef:        ref: Console

应用这些内容创立一个文件名log4j2.yaml并将log4j.configurationFile设置 为指向其地位。

接下来,运行应用程序。您将看到与以前雷同的输入。

09:38:14.114 [main] ERROR com.company.Main - Hello there!09:38:14.119 [main] FATAL com.company.Main - Hello there!

咱们曾经管制了应用程序的日志记录配置。当初让咱们改良它。

日志文件地位

第一步是将咱们的日志从控制台中取出并放入一个文件中。为此,咱们须要理解appender。

Appenders 将日志音讯放在它们所属的中央。默认配置提供一个控制台附加程序。顾名思义,它将音讯附加到控制台。

Appenders:  Console:    name: Console    target: SYSTEM_OUT    PatternLayout:      Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"

咱们想要一个文件附加程序。让咱们替换咱们的控制台 appender。

Appenders:  File:    name: File_Appender    fileName: logfile.log    PatternLayout:      Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"

文件附加器有一个name,就像控制台附加器一样。然而他们有一个fileName而不是target。

与控制台 appender 相似,它们也有一个PatternLayout,咱们将在上面介绍。

这个名字不仅仅是为了展现。如果咱们想用文件附加器替换控制台附加器,咱们须要让咱们的记录器 晓得在哪里搁置咱们的日志音讯。

因而,将记录器中的ref值更改为文件附加程序的名称。

Loggers:  Root:    level: error    AppenderRef:      ref: File_Appender

当初,从新运行应用程序。它没有记录到控制台,而是将音讯放在工作目录中名为logfile.log 的文件中。咱们已将日志移至文件中!

日志级别

在咱们的日志文件中,咱们依然只看到了六个日志音讯中的两个。让咱们谈谈记录器以及它们如何治理日志音讯。

咱们的根本配置定义了一个记录器。

Loggers:  Root:    level: error    AppenderRef:      ref: File_Appender

它有一个“谬误”级别,所以它只打印谬误或致命的音讯。

当记录器收到日志音讯时,它会依据其配置的级别传递或过滤它。此表显示了记录器配置和日志音讯级别之间的关系。

因而,如果咱们更改记录器的级别,咱们将看到更多音讯。将其设置为“调试”。

Loggers:  Root:    level: debug    AppenderRef:      ref: File_Appender

接下来,从新运行程序。应用程序记录所有调试级别或更高级别的音讯。

记录器层次结构
Log4j 按层次结构排列记录器。这使得为各个类指定不同的配置成为可能。

让咱们更改咱们的应用程序,看看它的实际效果。

public class Main {  private static final Logger logger = LogManager.getLogger(Main.class);  public static void main(String[] args) {    String message = "Hello there!";    System.out.println(message);    logger.debug(message);    logger.info(message);    logger.error(message);    LoggerChild.log();  }  private static class LoggerChild {    private static final Logger childLogger = LogManager.getLogger(LoggerChild.class);    static void log() {        childLogger.debug("Hi Mom!");    }  }}

咱们增加了一个外部类来创立一个记录器并用它记录一条音讯。

之后次要做了记录,它调用LoggerChild 。

如果咱们应用以后配置运行它,咱们会看到新音讯,并且它是从不同的类记录的。

12:29:23.325 [main] DEBUG com.company.Main - Hello there!12:29:23.331 [main] INFO  com.company.Main - Hello there!12:29:23.332 [main] ERROR com.company.Main - Hello there!12:29:23.333 [main] DEBUG com.company.Main.LoggerChild - Hi Mom!

记录器具备相似于 Java 的类层次结构。所有记录器都是迄今为止咱们始终在应用的根记录器的后辈。

短少任何特定配置的记录器继承根配置。

所以当 Main 和 LoggerChild 应用它们的类名创立记录器时,这些记录器继承了 Root 的配置,即向 File_Appender发送调试级别和更高级别的音讯 。

咱们能够笼罩这两个记录器的指定配置。

Loggers:  logger:    -      name: com.company.Main      level: error      additivity: false      AppenderRef:        ref: File_Appender    -      name: com.company.Main.LoggerChild      level: debug      additivity: false      AppenderRef:        ref: File_Appender  Root:    level: debug    AppenderRef:      ref: File_Appender

记录器在记录器局部命名 。因为咱们列出了两个,因而咱们应用 YAML 数组语法。

咱们设置 com.company.Main的 记录为“谬误”,并 com.company.Main.LoggerChild的 为“调试”。

该加设置管制的log4j是否会从记录仪的先人将音讯发送给后辈。

如果设置为 true,两个记录器将解决雷同的音讯。某些零碎心愿将雷同的音讯增加到两个不同的日志中。咱们不心愿呈现这种行为,因而咱们笼罩了默认值并指定了 false。

当初再次运行程序:

12:33:11.062 [main] ERROR com.company.Main - Hello there!12:33:11.073 [main] DEBUG com.company.Main.LoggerChild - Hi Mom!

咱们只看到来自Main的谬误音讯, 但依然看到来自LoggerChild的调试音讯!

不止一个 Appender

就像咱们能够领有多个 logger 一样,咱们也能够领有多个 appender。

让咱们对咱们的配置进行一些更改。

增加第二个文件附加程序。为此,请应用原始 appender 创立一个列表,并应用不同的名称和文件创建第二个列表。您的Appenders局部应如下所示:

  Appenders:    File:      -        name: File_Appender        fileName: logfile.log        PatternLayout:          Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"      -        name: Child_Appender        fileName: childlogfile.log        PatternLayout:          Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"

接下来,将 LoggerChild 记录器指向新的 appender。您的记录器局部将如下所示。

Loggers:   logger:     -      name: com.company.Main      level: error      additivity: false      AppenderRef:        ref: File_Appender     -      name: com.company.Main.LoggerChild      level: debug      additivity: false      AppenderRef:        ref: Child_Appender   Root:     level: debug     AppenderRef:      ref: File_Appender

当初运行该应用程序,您将看到两个不同的日志文件,每个文件都蕴含来自其关联类的音讯。

日志音讯格局
咱们的每个 appender 都有一个 PatternLayout。

PatternLayout:
Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"

PatternLayout 是 Log4j 布局类的一个实例。Log4j 具备用于以 CSV、JSON、Syslog 和各种不同格局记录音讯的内置布局。

PatternLayout 有一组用于格式化音讯的运算符,其操作相似于 C 的sprintf函数。通过指定模式,咱们能够管制由 appender 写入的日志音讯的格局。

咱们的布局字符串如下所示:

"%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"

每个 % 对应于日志音讯中的一个字段。

PatternLayout有许多额定的操作符。

变量替换

随着 appender 和 loggers 的减少,配置文件可能会变得反复。Log4j 反对变量替换以帮忙缩小反复并使其更易于保护。让咱们应用Properties 来优化咱们的配置。

Configuration:  status: warn  Properties:    property:      -        name: "LogDir"        value: "logs"      -        name: "DefaultPattern"        value: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"  Appenders:    File:      -        name: File_Appender        fileName: ${LogDir}/logfile.log        PatternLayout:          Pattern: ${DefaultPattern}      -        name: Child_Appender        fileName: ${LogDir}/childlogfile.log        PatternLayout:          Pattern: ${DefaultPattern}  Loggers:    logger:      -        name: com.company.Main        level: error        additivity: false        AppenderRef:          ref: File_Appender     -        name: com.company.Main.LoggerChild        level: debug        additivity: false        AppenderRef:          ref: Child_Appender    Root:      level: debug      AppenderRef:        ref: File_Appender

在文件的顶部,咱们申明了两个属性,一个名为LogDir,另一个名为DefaultPattern。

申明属性后,能够应用大括号和美元符号在配置中应用它: ${LogDir} 或${DefaultPattern}

LogDir 是咱们增加到两个日志文件名称中的子目录名称。当咱们运行应用程序时,log4j 将创立这个目录并将日志文件放在那里。

咱们指定DefaultPattern作为咱们两个日志文件的模式布局,将定义移到一个中央。如果咱们想批改咱们的日志文件格式,咱们当初只需放心更改一次。

Log4j 还能够从环境中导入属性。您能够在此处找到详细信息 。

例如,如果咱们想从 Java 零碎属性导入日志文件目录,咱们在 log4j 配置中将其指定为${sys : LogDir}并将 LogDir 零碎属性设置为所需的目录。

主动重新配置

Log4j 能够定期从新加载其配置,使咱们可能在不重新启动应用程序的状况下更改应用程序的日志记录配置。

将monitorInterval设置增加到文件的Configuration局部,log4j 将按指定的工夫距离扫描文件。

Configuration:  monitorInterval: 30

距离以秒为单位指定。

论断

Log4j 是一个弱小的日志框架,它容许咱们将应用程序配置为以各种不同的形式登录,并对不同组件如何应用日志文件进行精密管制。

本教程涵盖了配置 log4j 的根本方面,但还有很多货色须要学习。您能够在我的项目网站上理解 log4j 配置 。

这篇文章是由 Eric Goebelbecker 撰写的。Eric在纽约市的金融市场工作了 25 年,为市场数据和金融信息替换 (FIX) 协定网络开发基础设施。他喜爱议论什么使团队无效(或不那么无效!)