Log4j 2 API
Log4j 2 API:https://logging.apache.org/log4j/2.x/manual/api.html
Apache Log4j API 2.17.2 API:https://logging.apache.org/log4j/2.x/log4j-api/apidocs/overview-summary.html
概述
Log4j 2 API提供了应用程序应该编码到的接口,并提供了实现者创建日志实现所需的适配器组件。 虽然Log4j 2在API和实现之间进行了分解,但这样做的主要目的不是允许多个实现(虽然这当然是可能的),而是明确定义在“正常”应用程序代码中使用哪些类和方法是安全的。
你好世界!
Hello World!
没有习惯的Hello, World示例,介绍就不完整。 这里是我们的。 首先,从LogManager获取一个名为“HelloWorld”的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!");
}
}
声明:如果不想每次都写private final Logger logger = LoggerFactory.getLogger(当前类名.class); 可以在类上用注解 @Slf4j 。
注解@Slf4j的使用:https://www.jianshu.com/p/6e137ee836a1
根据所使用的配置,对logger.info()的调用的输出将有很大的不同。 有关更多细节,请参阅下面的Configuration配置部分。
Configuration 配置
将日志请求插入到应用程序代码中需要大量的计划和工作。 观察表明,大约有4%的代码用于日志记录。 因此,即使中等规模的应用程序的代码中也会嵌入数千条日志语句。 考虑到这些日志语句的数量,管理这些日志语句变得非常必要,而不需要手工修改它们。
Log4j 2的配置有四种方式:
通过以XML、JSON、YAML或属性格式编写的配置文件。
通过编程方式创建ConfigurationFactory和Configuration实现。
通过编程方式,调用Configuration接口中公开的api,将组件添加到默认配置中。
编程方式,通过调用内部Logger类的方法。
本页面主要关注通过配置文件配置Log4j。 关于以编程方式配置Log4j的信息可以在 extended Log4j 2和Programmatic Log4j Configuration中找到。
所有可用的格式在功能上是相同的。 例如,可以使用属性格式(或相反的格式)重写XML中的配置文件,而不会丢失任何功能。 然而,Log4j配置的层次性可以用自然支持嵌套的格式更好地捕获,因此XML、JSON和YAML文件通常更容易使用。
注意,与Log4j 1不同的是。 在Log4j . x中,Log4j . 2的公共API不公开添加、修改或删除附加器和过滤器或以任何方式操作配置的方法。
Substituting Parameters 代入参数
通常,日志记录的目的是提供关于系统中发生的事情的信息,这需要包括关于被操作的对象的信息。 在Log4j 1。 X这可以通过做以下事情来实现:
if (logger.isDebugEnabled()) {
logger.debug("Logging in user " + user.getName() + " with birthday " + user.getBirthdayCalendar());
}
重复这样做会使代码感觉更像是日志,而不是手头的实际任务。 此外,它导致日志级别被检查两次; 一次是调用isDebugEnabled,一次是调试方法。 更好的选择是:
logger.debug("Logging in user {} with birthday {}", user.getName(), user.getBirthdayCalendar());
对于高于日志级别的代码,只会检查一次,并且String构造只会在启用调试日志记录时发生。具体封装可查看logger.debug源码,这里不再讲述。
logger.isDebugEnabled() 日志级别过滤
首先这个问题涉及到了 log 日志的级别,
Logger共有6个log级别,按优先级由低到高排序分别是:
TRACE < DEBUG < INFO < WARN < ERROR < FATAL
他们分别对应Logger的trace, debug, info, warn, error和fatal方法进行输出,但是我们通常只使用debug、info和error这三个最常用的级别。运行时的log输出级别可以通过更改log4j配置文件来进行配置,就免去了注释掉debug代码的尴尬。
比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。如果设置级别为INFO,则优先级高于等于INFO级别(如:INFO、WARN、ERROR)的日志信息将可以被输出,小于该级别的如DEBUG将不会被输出。
当程序正式上线运营时,加入 logger.isDebugEnabled() 判断,如果日志级别不是debug 那么就跳过这个条件下的代码,排除调试日志,进而提高效率(打印少量日志,运行小量代码)
Formatting Parameters 格式化参数
如果logger参数toString()不是你想要的,那么Formatter记录器将格式化留给你。 为了方便格式化,可以使用与Java的Formatter相同的格式字符串。 Logger getFormatterLogger日志记录器允许您在消息中使用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
将 Loggers 与格式化 Loggers 混合
格式化程序记录器可以细粒度地控制输出格式,但缺点是必须指定正确的类型(例如,对于%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表达式的支持。 这允许客户端代码延迟记录消息,而无需显式地检查请求的日志级别是否启用。 例如,之前你可以这样写:
// 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 命名方法
大多数日志实现使用层次结构方案来匹配 logger 名称和日志配置。 在这个方案中,记录器名称层次结构由 ’ . ’ 点运算符表示。其方式与Java包名称使用的层次结构非常相似。 例如,org.apache.logging.appender和org.apache.logging.filter都将org.apache.logging作为它们的父节点。 在大多数情况下,应用程序通过将当前类的名称传递给LogManager.getLogger(…)来命名它们的记录器。 因为这种用法很常见,所以当日志记录器名称参数被省略或为空时,Log4j 2提供了这个默认值。 例如,在下面的所有例子中,Logger的名称都是“org.apache.test.MyTest”。
package org.apache.test;
public class MyTest {
// 1
private static final Logger logger = LogManager.getLogger(MyTest.class);
// 2
// private static final Logger logger = LogManager.getLogger(MyTest.class.getName());
// 3
// private static final Logger logger = LogManager.getLogger();
}