Log4j Warning: “No Appenders Could Be Found for Logger” – Log4j Warning: “No Appenders Could Be Found for Logger”

最后修改: 2021年 6月 5日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll show how to fix the warning, “log4j: WARN No appenders could be found for logger”. We’ll explain what an appender is and how to define it. Furthermore, we will show how to solve the warning in different ways.

在本教程中,我们将展示如何修复警告,“log4j: WARN No appenders could be found for logger”我们将解释什么是appender以及如何定义它。此外,我们还将展示如何以不同的方式解决该警告。

2. Appender Definition

2.应用者定义

Let’s first explain what an appender is. Log4j allows us to put logs into multiple destinations. Each destination where it prints output is called an appender. We have appenders for the console, files, JMS, GUI components, and others.

我们先来解释一下什么是appender。Log4j允许我们将日志放入多个目的地。每一个打印输出的目的地被称为appender。我们有用于控制台、文件、JMS、GUI组件等的appender。

There’s no default appender defined in log4j. Additionally, a logger can have multiple appenders, in which case the logger prints output into all of them.

log4j中没有定义默认的appender。 另外,一个记录器可以有多个appender在这种情况下,记录器会向所有appender打印输出。

3. Warning Message Explained

3.警告信息的解释

Now that we know what an appender is, let’s understand the issue at hand. The warning message says that no appender could be found for a logger.

现在我们知道了什么是appender,让我们来了解一下眼前的问题。警告信息说,无法为一个记录器找到应用者。

Let’s create a NoAppenderExample class to reproduce the warning:

让我们创建一个NoAppenderExample类来重现这个警告。

public class NoAppenderExample {
    private final static Logger logger = Logger.getLogger(NoAppenderExample.class);

    public static void main(String[] args) {
        logger.info("Info log message");
    }
}

We run our class without any log4j configuration. After this, we can see the warning together with more details in the console output:

我们在没有任何log4j配置的情况下运行我们的类。之后,我们可以在控制台输出中看到警告和更多细节。

log4j:WARN No appenders could be found for logger (com.baeldung.log4j.NoAppenderExample).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

4. Solving the Issue With Configuration

4.用配置来解决这个问题

Log4j looks by default into the application’s resources for a configuration file, which can be either in XML or Java properties format. Let’s now define the log4j.xml file under the resources directory:

Log4j默认在应用程序的资源中寻找一个配置文件,它可以是XML或Java属性格式。现在让我们在资源目录下定义log4j.xml文件。

<log4j:configuration debug="false">
    <!--Console appender -->
    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %p %m%n"/>
        </layout>
    </appender>

    <root>
        <level value="DEBUG"/>
        <appender-ref ref="stdout"/>
    </root>
</log4j:configuration>

We defined the root logger, which exists on the top of the logger’s hierarchy. All application loggers are children of it and override its configuration. We defined the root logger with one appender, which puts logs into the console.

我们定义了root 记录器,它存在于记录器层次结构的顶端。所有应用程序的日志记录器都是它的子女,并覆盖其配置。我们为root日志记录器定义了一个appender,它将日志放入控制台。

Let’s run the NoAppenderExample class again and check the console output. As a result, the log contains our statement:

让我们再次运行NoAppenderExample类并检查控制台的输出。结果是,日志中包含了我们的语句。

2021-05-23 12:59:10 INFO Info log message

4.1. Appender Additivity

4.1.应用者的可加性

An appender doesn’t have to be defined for each logger. The logging request for a given logger sends logs to the appenders defined for it and all appenders specified for loggers higher in the hierarchy. Let’s show it in an example.

不一定要为每个记录仪定义一个应用者。给定日志记录器的日志请求会将日志发送到为其定义的appender以及为层次结构中更高的日志记录器指定的所有appender。让我们用一个例子来说明。

If logger A has defined a console appender and logger B is a child of A, logger B prints its logs to the console, too. A logger inherits appenders from its ancestor only when additivity flags in the intermediate ancestors are set to true. In case the additivity flag is set to false, appenders from loggers higher in the hierarchy are not inherited.

如果日志记录器A定义了一个控制台应用程序,并且日志记录器BA的一个子程序,那么日志记录器B也将其日志打印到控制台。只有当中间的祖先中的additivity标志被设置为true时,日志记录器才会从其祖先中继承appender。如果additivity标志被设置为false,则不会继承层次结构中更高的日志记录器的appender。

To prove that a logger inherits appenders from ancestors, let’s add a logger for NoAppenderExample in our log4j.xml file:

为了证明logger从祖先那里继承appenders,让我们在log4j.xml 文件中为NoAppenderExample添加一个logger

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
<log4j:configuration debug="false">
    ...
    <logger name="com.baeldung.log4j.NoAppenderExample" />
    ...
</log4j:configuration>

Let’s run the NoAppenderExample class again. This time, the log statement appears in the console. Though the NoAppenderExample logger has no appender explicitly defined, it inherits the appender from the root logger.

让我们再次运行NoAppenderExample类。这一次,日志语句出现在控制台中。尽管NoAppenderExample日志器没有明确定义appender,但它从root日志器继承了appender

5. Configuration File Not on the Classpath

5.配置文件不在类路径上

Let’s now consider the case where we want to define the configuration file outside an application classpath. We have two options:

现在让我们考虑一下,我们想在应用程序classpath之外定义配置文件的情况。我们有两个选择。

  • Specify a path to the file with the java command line option: -Dlog4j.configuration=<path to log4j configuration file>
  • Define path in code: PropertyConfigurator.configure(“<path to log4j properties file>”);

In the next section, we’ll see how to achieve this in our Java code.

在下一节,我们将看到如何在我们的Java代码中实现这一点。

6. Solving the Issue in Code

6.在代码中解决这个问题

Let’s say we don’t want the configuration file. Let’s remove the log4.xml file and modify the main method:

假设我们不想要这个配置文件。让我们删除log4.xml文件并修改main方法。

public class NoAppenderExample {
    private final static Logger logger = Logger.getLogger(NoAppenderExample.class);

    public static void main(String[] args) {
        BasicConfigurator.configure();
        logger.info("Info log message");
    }
}

We call the static configure method from the BasicConfigurator class. It adds the ConsoleAppender to the root logger. Let’s look at the source code of the configure method:

我们从BasicConfigurator类中调用静态configure方法。它将ConsoleAppender添加到rootlogger。让我们看一下configure方法的源代码。

public static void configure() {
    Logger root = Logger.getRootLogger();
    root.addAppender(new ConsoleAppender(new PatternLayout("%r [%t] %p %c %x - %m%n")));
}

Because the root logger in log4j always exists, we can programmatically add the console appender to it.

由于log4j中的root记录器始终存在,我们可以通过编程将控制台应用程序添加到其中。

7. Conclusion

7.结语

That concludes this short tutorial on how to solve the log4j warning about a missing appender. We explained what an appender is and how to solve the warning issue with a configuration file. Then, we explained how appender additivity works. Finally, we showed how to solve the warning in code.

关于如何解决log4j关于缺少appender的警告的简短教程到此结束。我们解释了什么是appender以及如何用配置文件来解决警告问题。然后,我们解释了appender的可添加性是如何工作的。最后,我们展示了如何在代码中解决这个警告。

As always, the source code of the example is available over on GitHub.

一如既往,该示例的源代码可在GitHub上获得over