在我前一篇文章Log4j2 简单使用中介绍了一些Log4j2的简单使用方法。下面来做一些进阶介绍。
使用属性
在复杂的项目中,可能有一些约定的属性比如项目名称、配置文件路径等等。这些属性可能会在多个日志的配置中用到。这样就可以将这些属性配置到Log4j2的配置文件中,方便在多个Logger中共享。
定义属性需要在配置文件中添加properties节点,然后添加多个property。配置完成之后使用${property_name}
就可以在项目中引用了。正如下面的一个配置文件中PatternLayout这样。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<properties>
<property name="logger_name">
FuckLog4j2
</property>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level [${logger_name}] %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
配置完成之后,就可以运行一下程序看看效果了。随便打印一下Logger,发现出现如下输出。我们成功的定义了一个属性并在Logger中使用。
18:05:09.404 [Test worker] INFO [FuckLog4j2] yitian.bean.BeanTest - Pi is 3.141592653589793
自动重新配置
有时候可能在项目运行的时候修改一些日志配置,Log4j2也支持定时重新读取配置的功能。需要在配置文件根节点也就是Configuration节点下添加一个属性monitorInterval,指定在多少秒后重新读取配置,单位是秒,最低读取间隔是5秒。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="30">
...
</Configuration>
布局配置
前面简单说了一下PatternLayout布局配置,这种布局会根据指定的格式化字符串将数据日志格式化成相应的字符串。其实除了这种布局之外,还可以将日志打印为HTML、XML、YAML、CVS等多种格式的文件。
下面的配置文件定义了一个HTMLLayout,这样会把日志输出位一个HTML文件,日志内容会议表格列出。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<properties>
<property name="log_path">
D:\Desktop
</property>
<property name="file_name">
log.html
</property>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="File" fileName="${log_path}\${file_name}">
<HTMLLayout title="日志"/>
</File>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
运行程序之后会有这么一个HTML文件,打开以后大致就是这样的。其他布局的使用方法也是类似的,添加到对应的Appender下,然后指定相应布局的属性,就可以获得对应的效果。详细情况可以查看官方文档Log4j2 - Lyaout,这里列出了所有的布局和布局对应的属性。
Appender配置
除了我们用到的控制台和文件之外,还有很多Appender,可以满足我们的大部分需求。下面介绍一个非常实用的Appedner——RollingRandomAccessFileAppender,这个Appender会将日志写入文件,当满足条件时还会执行“rollover”操作,也就是将旧日志打包为一个压缩文件并创建一个新文件用来记录日志。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<properties>
<property name="log_path">
D:\Desktop
</property>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<RollingRandomAccessFile
name="RollingRandomAccessFile"
fileName="${log_path}\log.txt"
filePattern="${log_path}\logs/app-%d{yyyy-MM-dd}-%i.log.zip">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="250 MB"/>
<OnStartupTriggeringPolicy/>
</Policies>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingRandomAccessFile"/>
</Root>
</Loggers>
</Configuration>
RollingRandomAccessFile节点有一个filePattern属性,指定打包的日志文件的格式。还有一个Policies节点,指定什么之后执行rollover。常用的有这么三个策略:
- OnStartupTriggeringPolicy 程序启动时候执行一次rollover
- SizeBasedTriggeringPolicy 日志文件到达指定大小是执行rollover,单位可以使KB、MB、GB。
- TimeBasedTriggeringPolicy 当日期不匹配的时候执行rollover。例如上面定义的filePattern是
${log_path}\logs/app-%d{yyyy-MM-dd}-%i.log.zip
,日期格式包含年月日,那么就会每天执行一次rollover。它有两个可定义的属性,一个是interval,表示rollover的间隔,单位是日期的最小单位。比如如果日期是%d{yyyy-MM-dd-HH}
,那么interval="6"
意思就是每隔六个小时。另一个属性是modulate,指定是否调整rollover的间隔。假如现在是上午3点,间隔是4个小时,当modulate为false的时候下次rollover就是上午七点,以此类推,如果modulate是true下次rollover就是上午4点,然后以此类推。
除了这几个我们知道的Appender之外,还有许多其他的Appender,可以将日志输出至SQL数据库、NoSQL数据库,电子邮件等多种目的地。详细情况参见Log4j2 - Appenders。
过滤器
Log4j2还支持过滤器功能,可以定义为全局、也可以定义到Appender或者Logger上。过滤器支持时间、日志级别、日志内容等多种过滤方式。详细的过滤器类型和用法,参见Log4j2 - Filters。
下面的配置文件定义了一个日志级别过滤器ThresholdFilter,将error以上的日志信息输出到文件上。所有过滤器都有两个属性onMatch和onMismatch,指定匹配过滤器和不匹配过滤器时候执行的操作,有三个取值ACCEPT
,DENY
,NEUTRAL
。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="File" fileName="D:/Desktop/log.txt">
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
其它API
前面我们使用了最简单的方式定义和使用Logger,也就是下面的两句代码。
Logger logger = LogManager.getLogger();
logger.info("info");
除了这种简单的方式,Log4j2还提供了其它API,帮助我们执行更加复杂的操作。
格式化信息
比如说我们要在日志中输出用户名和密码两个信息,可以编写如下的语句,字符串中的{}
是占位符,会被后面的实际参数替换。
logger.info("username:{} password:{}", username, password);
如果需要更精细的格式化,可以使用%-5s这样的格式化字符串,但是相应地需要一个格式化的Logger,这需要使用LogManager.getFormatterLogger()
语句。
Logger logger = LogManager.getFormatterLogger();
String username = "root";
String password = "123456";
logger.debug("Logging in user %s with birthday %s", username, Calendar.getInstance());
logger.debug("Logging in user %1$s with birthday %2$tm %2$te,%2$tY", username, Calendar.getInstance());
logger.debug("Integer.MAX_VALUE = %,d", Integer.MAX_VALUE);
logger.debug("Long.MAX_VALUE = %,d", Long.MAX_VALUE);
日志标记
在输出日志的时候,可以为日志添加一个标记,这样在日志数出的时候就会附带上这个标记,帮助我们区分不同的日志。调用MarkerManager.getMarker方法生成一个标记,标记必须是唯一的。然后在记录日志的时候将标记传入。
Logger logger = LogManager.getLogger();
String username = "root";
String password = "123456";
Marker marker = MarkerManager.getMarker("test");
logger.debug(marker, "username:{} password:{}", username, password);
为了能在日志输出时看到标记,我们需要在PatternLayout的pattern属性中添加%marker
。
流跟踪
这需要4个方法entry()、traceEntry()、exit()、traceExit(),前两个方法用在方法的开始处,后两个方法用在方法结束时(return语句之前),一三方法为一对,二四方法为一对。entry()和traceEntry()的区别在于,前者接受一组参数,一般情况下是所在方法的参数,后者接受一个格式化字符串和一组参数。这几个方法会使用trace级别和ENTER
或EXIT
标记记录日志。由于traceEntry方法能接受格式化字符串,所以这个方法更常用一些。
我们新建一个类,然后在它的方法中添加流跟踪语句。
public class MyTest {
private static Logger logger = LogManager.getLogger();
public static String test(String name, int id) {
logger.traceEntry("name:{} id:{}", name, id);
return logger.traceExit(name + ":" + id);
}
}
然后调用这个方法,就可以在日志中看到对应的流信息了。因为流信息都是TRACE级别的,所以如果日志级别是其他的级别,就无法看到这些信息了。
21:56:38.755 ENTER[ FLOW ] [Test worker] TRACE yitian.bean.MyTest - Enter name:yitian id:1
21:56:38.771 EXIT[ FLOW ] [Test worker] TRACE yitian.bean.MyTest - Exit with(yitian:1)
以上就是一些Log4j2的进阶用法。由于Log4j2框架的内容实在太多,我完全写不过来,所以就此打住了。