关于Log
org.apache.commons.logging
使用日志一般需要获取一个Log对象,在类中声明一个私有属性Log
private static Log log = LogFactory.getLog(Test.class);
org.apache.commons.logging.LogFactory
部分代码分析:
通过静态方法来选择日志实现,默认是LogApi.JUL(JUL:java.util.logging)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public abstract class LogFactory {
private static LogApi logApi = LogApi.JUL;
static { ClassLoader cl = LogFactory.class.getClassLoader(); try { // Try Log4j 2.x API cl.loadClass("org.apache.logging.log4j.spi.ExtendedLogger"); logApi = LogApi.LOG4J; } catch (ClassNotFoundException ex1) { try { // Try SLF4J 1.7 SPI cl.loadClass("org.slf4j.spi.LocationAwareLogger"); logApi = LogApi.SLF4J_LAL; } catch (ClassNotFoundException ex2) { try { // Try SLF4J 1.7 API cl.loadClass("org.slf4j.Logger"); logApi = LogApi.SLF4J; } catch (ClassNotFoundException ex3) { // Keep java.util.logging as default } } } //枚举属性 private enum LogApi {LOG4J, SLF4J_LAL, SLF4J, JUL} }
|
getLog中的参数测试
测试所用日志maven依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <!-- junit测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> </dependency>
|
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package log;
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;
/** * 关于日志的测试 * 本次测试使用的commons-logging作为日志门面 * 如果有Log4j,commons-logging的LogFactory初始化静态方法会自动选择日志实现 * LogFactory中的枚举属性:private enum LogApi {LOG4J, SLF4J_LAL, SLF4J, JUL} * JUL: java.util.logging(JDK自带的Logging其实是一个鸡肋,竟然没有debug的日志级别,没测试过) * log4j:只要我们在项目中添加了log4j的jar包,那么commons-logging就会自动切到log4j的日志输出。 * log4j必须要有log4j.properties * @author Momentonly * @date 2020/4/20 */ public class LogTest {
}
|
log4j的配置文件
1 2 3 4 5 6 7 8 9 10
| # Global logging configuration log4j.rootLogger=DEBUG, stdout
#设置包级别的日志 #log4j.logger.log=DEBUG
# Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] %l - %m%n
|
测试方法1
getLog传递一个本类的Class对象
1 2 3 4 5 6 7 8 9
| //获取一个日志对象 private static Log log = LogFactory.getLog(LogTest.class);
@Test public void test1(){ log.debug("debug()..."); log.info("start..."); log.warn("end."); }
|
打印:
DEBUG [main] log.LogTest.test1(LogTest.java:26) - debug()…
INFO [main] log.LogTest.test1(LogTest.java:27) - start…
WARN [main] log.LogTest.test1(LogTest.java:28) - end.
测试方法2
getLog传递一个字符串参数
1 2 3 4 5 6 7 8 9
| //获取一个日志对象 private static Log log = LogFactory.getLog("这是一个测试类");
@Test public void test2(){ log.debug("debug()..."); log.info("start..."); log.warn("end."); }
|
打印:
DEBUG [main] log.LogTest.test2(LogTest.java:32) - debug()…
INFO [main] log.LogTest.test2(LogTest.java:33) - start…
WARN [main] log.LogTest.test2(LogTest.java:34) - end.
测试方法3
getLog传递任意一个Class参数
1 2 3 4 5 6 7 8 9
| //获取一个日志对象 private static Log log = LogFactory.getLog(Object.class);
@Test public void test3(){ log.debug("debug()..."); log.info("start..."); log.warn("end."); }
|
打印:
DEBUG [main] log.LogTest.test3(LogTest.java:25) - debug()…
INFO [main] log.LogTest.test3(LogTest.java:26) - start…
WARN [main] log.LogTest.test3(LogTest.java:27) - end.
测试1,2,3方法总结
发现打印结果的追踪类并没有因为getLog的参数不同而发生改变
测试方法4
修改log4j配置文件,关闭日志
1
| log4j.rootLogger=OFF, stdout
|
测试方法
1 2 3 4 5 6 7 8 9
| //获取一个日志对象 private static Log log = LogFactory.getLog(Object.class);
@Test public void test4(){ log.debug("debug()..."); log.info("start..."); log.warn("end."); }
|
没有任何输出
测试方法5
修改log4j配置文件
1 2 3
| log4j.rootLogger=OFF, stdout #设置包级别的输出 log4j.logger.java.lang=DEBUG
|
测试方法
1 2 3 4 5 6 7 8 9
| //获取一个日志对象 private static Log log = LogFactory.getLog(Object.class);
@Test public void test5(){ log.debug("debug()..."); log.info("start..."); log.warn("end."); }
|
打印:
1 2 3
| DEBUG [main] log.LogTest.test5(LogTest.java:25) - debug()... INFO [main] log.LogTest.test5(LogTest.java:26) - start... WARN [main] log.LogTest.test5(LogTest.java:27) - end.
|
测试4,5方法总结
getLog中的参数不会使调用该日志的类(追踪类)发生改变
但是,该参数是Class对象,可以设置包,类,方法级别来定义log4j的输出
(例如在mybatis中通过日志打印sql就设置包级别为你的接口包就可以,但是
打印的日志追踪类却不是你的接口实现类)
log4j2
Log4j2简介
log4j2是log4j 1.x 的升级版,2015年5月,Apache宣布log4j1.x 停止更新。最新版为1.2.17。
log4j2参考了logback的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升,主要有:
1、异常处理:在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。
2、性能提升:log4j2相较于log4j 1和logback都具有很明显的性能提升。
3、自动重载配置:参考了logback的设计,提供自动刷新参数配置,可以动态的修改日志的级别而不需要重启应用。
4、无垃圾机制,log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的jvm gc。
测试
引入依赖
1 2 3 4 5 6 7 8 9 10 11
| <!--添加log4j2相关jar包--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version> </dependency>
|
配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <?xml version="1.0" encoding="UTF-8"?> <configuration status="error"> <!--先定义所有的appender --> <appenders> <!--这个输出控制台的配置 --> <Console name="Console" target="SYSTEM_OUT"> <!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) --> <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/> <!-- 这个都知道是输出日志的格式 --> <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> </Console> <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用 --> <!--append为TRUE表示消息增加到指定文件中,false表示消息覆盖指定的文件内容,默认值是true --> <File name="log" fileName="D:/logs/log4j2.log" append="false"> <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> </File> <!--添加过滤器ThresholdFilter,可以有选择的输出某个级别以上的类别 onMatch="ACCEPT" onMismatch="DENY"意思是匹配就接受,否则直接拒绝 --> <File name="ERROR" fileName="D:/logs/error.log"> <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/> </File> <!--这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 --> <RollingFile name="RollingFile" fileName="D:/logs/web.log" filePattern="logs/$${date:yyyy-MM}/web-%d{MM-dd-yyyy}-%i.log.gz"> <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/> <SizeBasedTriggeringPolicy size="2MB"/> </RollingFile> </appenders> <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 --> <loggers> <root level="trace"> <appender-ref ref="RollingFile"/> <appender-ref ref="Console"/> <appender-ref ref="ERROR" /> <appender-ref ref="log"/> </root> </loggers> </configuration>
|
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class log4j2Test { private static Logger logger= LogManager.getLogger(LogManager.ROOT_LOGGER_NAME); public static void main(String[] args) { for(int i=0;i<3;i++){ // 记录trace级别的信息 logger.trace("log4j2日志输出:This is trace message."); // 记录debug级别的信息 logger.debug("log4j2日志输出:This is debug message."); // 记录info级别的信息 logger.info("log4j2日志输出:This is info message."); // 记录error级别的信息 logger.error("log4j2日志输出:This is error message."); } } }
|
log4j2配置说明
log4j 2.x版本不再支持像1.x中的.properties后缀的文件配置方式,2.x版本常用.xml后缀的文件进行配置,除此之外还包含.json和.jsn配置文件
log4j2虽然采用xml风格进行配置,依然包含三个组件,分别是 Logger(记录器)、Appender(输出目的地)、Layout(日志布局)。
XML配置文件解析
1、根节点Configuration有两个属性:status和monitorinterval,有两个子节点:Appenders和Loggers(表明可以定义多个Appender和Logger).
1 2
| status用来指定log4j本身的打印日志的级别. monitorinterval为log4j 2.x新特点自动重载配置。指定自动重新配置的监测间隔时间,单位是s,最小是5s。
|
2、Appenders节点,常见的有三种子节点:Console、File、RollingFile
1 2 3
| Console节点用来定义输出到控制台的Appender. File节点用来定义输出到指定位置的文件的Appender. RollingFile节点用来定义超过指定大小自动删除旧的创建新的的Appender.
|
通过在子节点中加入\进行日志布局
;)
1 2 3 4 5 6 7 8
| %c 输出所属类的全名,可写为 %c{Num} ,Num类名输出的范围 如:"com.sun.aaa.classB",%C{2}将使日志输出输出范围为:aaa.classB %d 输出日志时间其格式为 可指定格式 如 %d{HH:mm:ss}等 %l 输出日志事件发生位置,包括类目名、发生线程,在代码中的行数 %n 换行符 %m 输出代码指定信息,如info(“message”),输出message %p 输出日志的优先级,即 FATAL ,ERROR 等 %r 输出从启动到显示该条日志信息所耗费的时间(毫秒数) %t 输出产生该日志事件的线程名
|
;)
3、Loggers节点,常见的有两种:Root和Logger.
Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出
Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。
logback log4j log4j2 性能实测

可见在同步日志模式下, Logback的性能是最糟糕的
而log4j2的性能无论在同步日志模式还是异步日志模式下都是最佳的
参考:https://www.cnblogs.com/LemonFive/p/10737658.html