Log4j 2 API

Overview

Log4j 2 API 提供了应用程序应该编码的接口,并提供了实现者创建日志记录实现所需的适配器组件。尽管 Log4j 2 在 API 和实现之间是分开的,但这样做的主要目的不是允许多个实现(尽管这是可能的),但要明确定义在“常规”应用程序代码中可以安全使用的类和方法。 。

Hello World!

没有惯用的 Hello,World 示例,没有任何介绍是完整的。这是我们的。首先,从LogManager获得名称为“ HelloWorld”的 Logger。接下来,使用 Logger 编写“ Hello,World!”。消息,但是仅当 Logger 配置为允许参考消息时,才会写入消息。

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class HelloWorld {
    private static final Logger logger = LogManager.getLogger("HelloWorld");
    public static void main(String[] args) {
        logger.info("Hello, World!");
    }
}

调用 logger.info()的输出将根据所使用的配置而有很大不同。有关更多详细信息,请参见Configuration部分。

Substituting Parameters

通常,日志记录的目的是提供有关系统中正在发生的事情的信息,这需要包括有关被操纵对象的信息。在 Log4j 1.x 中,可以通过执行以下操作来完成:

if (logger.isDebugEnabled()) {
    logger.debug("Logging in user " + user.getName() + " with birthday " + user.getBirthdayCalendar());
}

重复执行此操作的效果是使代码看起来更像是日志记录而不是手头的实际任务。此外,它还会导致对日志记录级别进行两次检查。一次调用 isDebugEnabled,一次调用 debug 方法。更好的选择是:

logger.debug("Logging in user {} with birthday {}", user.getName(), user.getBirthdayCalendar());

如果代码高于日志记录级别,则将仅检查一次,并且仅在启用调试日志记录时才会进行字符串构造。

Formatting Parameters

如果 toString()不是您想要的格式,Logger 记录程序将由您决定是否进行格式化。为了便于格式化,可以使用与 Java 的Formatter相同的格式字符串。例如:

public static Logger logger = LogManager.getFormatterLogger("Foo");

logger.debug("Logging in user %s with birthday %s", user.getName(), user.getBirthdayCalendar());
logger.debug("Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar());
logger.debug("Integer.MAX_VALUE = %,d", Integer.MAX_VALUE);
logger.debug("Long.MAX_VALUE = %,d", Long.MAX_VALUE);

要使用格式化程序 Logger,必须调用 LogManager getFormatterLogger方法之一。此示例的输出显示,与自定义格式相比,Calendar toString()是冗长的:

2012-12-12 11:56:19,633 [main] DEBUG: User John Smith with birthday java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=1995,MONTH=4,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=23,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
2012-12-12 11:56:19,643 [main] DEBUG: User John Smith with birthday 05 23, 1995
2012-12-12 11:56:19,643 [main] DEBUG: Integer.MAX_VALUE = 2,147,483,647
2012-12-12 11:56:19,643 [main] DEBUG: Long.MAX_VALUE = 9,223,372,036,854,775,807

将 Logger 与格式化 Logger 混合

格式化程序 Logger 可以对输出格式进行细粒度的控制,但缺点是必须指定正确的类型(例如,为%d 格式参数传递除十进制整数以外的任何值都会产生异常)。

如果您的主要用法是使用\ {} -style 参数,但是有时您需要对输出格式进行细粒度控制,则可以使用 printf 方法:

public static Logger logger = LogManager.getLogger("Foo");

logger.debug("Opening connection to {}...", someDataSource);
logger.printf(Level.INFO, "Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar());

Java 8 lambda 支持延迟日志记录

在版本 2.4 中,Logger 接口添加了对 lambda 表达式的支持。这允许 Client 端代码懒惰地记录消息,而无需显式检查是否已启用请求的日志级别。例如,以前您将编写:

// pre-Java 8 style optimization: explicitly check the log level
// to make sure the expensiveOperation() method is only called if necessary
if (logger.isTraceEnabled()) {
    logger.trace("Some long-running operation returned {}", expensiveOperation());
}

使用 Java 8,您可以使用 lambda 表达式实现相同的效果。您不再需要显式检查日志级别:

// Java-8 style optimization: no need to explicitly check the log level:
// the lambda expression is not evaluated if the TRACE level is not enabled
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());

Logger Names

大多数日志记录实现都使用分层方案,以使日志 Logger 名称与日志记录配置相匹配。在此方案中,Logger 名称层次结构由“。”表示。Logger 名称中的字符,其格式与 Java 包名称所使用的层次结构非常相似。例如,org.apache.logging.appender 和 org.apache.logging.filter 都以 org.apache.logging 作为其父项。在大多数情况下,应用程序通过将当前类的名称传递给 LogManager.getLogger(...)来为其 Logger 命名。因为这种用法很常见,所以当 logger 名称参数省略或为 null 时,Log4j 2 会将其作为默认值。例如,在下面的所有示例中,Logger 的名称均为“ org.apache.test.MyTest”。

package org.apache.test;

public class MyTest {
    private static final Logger logger = LogManager.getLogger(MyTest.class);
}
package org.apache.test;

public class MyTest {
    private static final Logger logger = LogManager.getLogger(MyTest.class.getName());
}
package org.apache.test;

public class MyTest {
    private static final Logger logger = LogManager.getLogger();
}