Log4j 2 API

总览

原文地址

Log4j 2提供一些应用程序应该编码使用的接口,并提供实现者创建一个日志实现所需的适配器组件。虽然Log4j 2将API和实现相分离,但这样做的主要目的并不是为了允许多实现,尽管那当然是可能的,但实际上是为了明确定义什么样子的类和方法在“普通”应用代码中是可安全使用的。

Hello World!

没有什么完整的介绍中没有最通常的Hello World示例。这是我们的。首先,从LogManager中获取一个名为“HelloWorld”的Logger。下一步,这个Logger用来写下“Hello, World!”消息,然而这条消息只会在Logger被配置为允许info级的消息时才会被写下。

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()的输出会明显因使用的配置而不同。查看配置一节获取更多细节。

参数替换

日志的目的通常是提供一些关于系统中正在发生什么的信息,同样也包含一些正在操作的对象信息。在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());

以上代码中日志级别只会被检查一次,而且只有在debug日志被启用时才会进行字符串拼接。

参数格式化

如果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,你必须调用LoggerManager中的getFormatterLogger方法。这个例子的输出展示了Canlendar的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参数传递一个小数将会抛出异常)。

如果你主要使用{}风格的参数,但偶尔需要精细粒度的输出格式控制,你可以使用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表达式的支持。这允许客户端代码延迟地记录消息,而不需要明确地检查日志级别是否可用。例如,之前你会这样写:

// Java 8之前的优化做法:显示地检查日志级别
// 以确保expensiveOperation()方法只有在必要时才会被调用
if (logger.isTraceEnabled()) {
    logger.trace("Some long-running operation returned {}", expensiveOperation());
}

通过Java 8你可以用lambda表达式大多同样效果。你不再需要显示检查日志级别:

// Java 8风格的优化:不再需要显示检查日志级别
// lambda表达式在TRACE等级不可用时不会被执行
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());

Logger名称

多数的日志实现使用层级模式来通过日志配置匹配logger名称。这种模式中logger名称是由“.”符号层级地进行命名的,和非常流行的Java包命名类似。例如,org.apache.logging.appender和org.apache.logging.filter都有org.apache.logging作为父亲。在多数用例中,应用程序通过传递当前类的名称到LogManager.getLogger中来命名它们的Logger。因为这种用法太常见,Log4j 2会在logger名称被忽略或位null时将这设为默认。下面所有的例子中,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();
}

results matching ""

    No results matching ""