一、应用场景
在某些特定的功能类中,要完成一些精简有用的输出日志,此时,不能仅仅依靠默认的日志级别(info,error,debug等)控制日志输出。这时候需要考虑自定义日志的实现。
目标:对一个特定业务可以输出与该业务相关的日志
通过解读官方文档自定义日志,发现LOG4J2支持自定义日志,自定义日志等级可以在代码或配置文件中实现。
http://logging.apache.org/log4j/log4j-2.8/manual/customloglevels.html
代码中,可以使用Level.forName()自定义日志等级。如:final Level VERBOSE = Level.forName("VERBOSE", 550);
注:intLevel越大,日志等级越低,error=200,warn=300,info=400,debug=500,trace=600
配置文件中自定义日志等级与片段(可直接跳过该片段到下面的简单实现):
二、简单实现
1.依赖文件pom.xml
org.apache.logging.log4j
log4j-api
2.7
org.apache.logging.log4j
log4j-core
2.7
org.apache.logging.log4j
log4j-slf4j-impl
2.4.1
com.lmax
disruptor
3.3.6
org.slf4j
slf4j-api
1.7.19
org.projectlombok
lombok
1.16.20
2.日志配置文件src/main/resources/log4j2.xml
3.自定义日志类XXBizLogger.java
package com.jupiter.log4j2;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;
/**log4j2日志扩展,支持业务日志
* 业务日志为最高级别
* 使用方式与扩展前基本相同:
* 使用XXBizLogger log=XXBizLogger.getLogger(loggerName);
* 替代原来的:Logger log=LogManager.getLogger(loggerName);
* 记录用于数据分析的业务日志 使用log.xxBiz(msg);
*
*/
public final class XXBizLogger extends ExtendedLoggerWrapper {
private static final long serialVersionUID = 103418572168533L;
private final ExtendedLoggerWrapper logger;
private static final String FQCN = XXBizLogger.class.getName();
private static final Level XXBIZ = Level.forName("XXBIZ", 450);//要小于等于自定义的xml文件中的等级
private XXBizLogger(final Logger logger) {
super((AbstractLogger) logger, logger.getName(), logger.getMessageFactory());
this.logger = this;
}
public static XXBizLogger getLogger() {
final Logger wrapped = LogManager.getLogger();
return new XXBizLogger(wrapped);
}
public static XXBizLogger getLogger(final Class> loggerName) {
final Logger wrapped = LogManager.getLogger(loggerName);
return new XXBizLogger(wrapped);
}
public void xxBiz(final String message) {
logger.logIfEnabled(FQCN, XXBIZ, null, message, (Throwable) null);
}
public void xxBiz(final String message, final Throwable t) {
logger.logIfEnabled(FQCN, XXBIZ, null, message, t);
}
}
4.测试类
package com.jupiter.log4j2.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Jupiter
* @description Slf4j+log4j2测试
* @date 2018年12月7日
*/
public class Test {
private static final Logger logger = LoggerFactory.getLogger(Test.class) ;
public static void main(String[] args) throws InterruptedException {
try {
String name = null;
name.length();
} catch (Exception e) {
for(int i=0; i<30; i++) {
logger.error("这是ERROR日志",e);//打到monitor日志
logger.warn("这是WARN日志",e);//xml中没设定该等级日志存放文件,所有日志中都不打印这条
logger.info("获取当前时间异常,info",e);//打印到info日志
//logger.xxBiz("获取当前时间异常,栈信息:",e);通常用的logger没有此方法
logger.debug("这是DEBUG日志",e);//等级不够,所有日志中都不打印这条
}
}
}
}
--------------第二个测试类------------------
package com.jupiter.log4j2.test;
import com.jupiter.log4j2.XXBizLogger;
/**
* @author Jupiter
* @description Slf4j+log4j2测试
* @date 2018年12月7日
*/
public class Test2 {
private static final XXBizLogger logger = XXBizLogger.getLogger(Test2.class) ;
public static void main(String[] args) {
try {
String name = null;
name.length();
} catch (Exception e) {
for(int i=0; i<30; i++) {
logger.error("这是ERROR日志",e);//打到monitor日志
logger.warn("这是WARN日志",e);//xml中没设定该等级日志存放文件,所有日志中都不打印这条
logger.info("这是INFO日志",e);//打印到info日志
logger.xxBiz("这是XXBIZ日志:",e);//自定义日志到指定文件中
logger.debug("这是DEBUG日志",e);//等级不够,所有日志中都不打印这条
}
}
}
}
5.测试(在测试中,会发现日志少打印的情况,这可能和异步日志输出有关)
运行Test.java结果
运行Test2.java结果
三、深入理解和使用
1.log4j2.xml文件中的三层范围约束:
第一层输出日志级别控制(所有日志先从这开始第一层过滤,不通过则不打印):
第二层输入日志级别控制(指定的日志输出文件存放最低级别日志):
第三层通过Filter节点过滤
2.在log4j2.xml文件中只定义的各个日志文件存什么等级范围的日志(即XXBizLogger定义的final Level XXBIZ的xxBiz方法输出的日志级别,非自定义的日志级别默认),交集尽量为空集☆
3.新写的日志类主要构造了新的日志输出方法及新方法的打日志方法的等级
4.如果想打出更多特定的日志,就在XXBizLogger中定义对应的日志等级与对应方法private static final Level XXBIZ = Level.forName("XXBIZ", 450);//要小于等于自定义的xml文件中的等级
写常用的方法即可:
public void xxBiz(final String msg) {
logger.logIfEnabled(FQCN, XXBIZ, null, msg, (Throwable) null);
}
public void xxBiz(final String msg, final Throwable t) {
logger.logIfEnabled(FQCN, XXBIZ, null, msg, t);
}
四、实现原理