文章目录
  1. 1. 关于Log
    1. 1.1. org.apache.commons.logging
      1. 1.1.1. org.apache.commons.logging.LogFactory
    2. 1.2. getLog中的参数测试
      1. 1.2.1. 测试所用日志maven依赖
      2. 1.2.2. 测试类
      3. 1.2.3. log4j的配置文件
      4. 1.2.4. 测试方法1
      5. 1.2.5. 测试方法2
      6. 1.2.6. 测试方法3
      7. 1.2.7. 测试1,2,3方法总结
      8. 1.2.8. 测试方法4
      9. 1.2.9. 测试方法5
      10. 1.2.10. 测试4,5方法总结
  2. 2. log4j2
    1. 2.1. 测试
    2. 2.2. log4j2配置说明

关于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 性能实测

img

可见在同步日志模式下, Logback的性能是最糟糕的

而log4j2的性能无论在同步日志模式还是异步日志模式下都是最佳的

参考:https://www.cnblogs.com/LemonFive/p/10737658.html

文章目录
  1. 1. 关于Log
    1. 1.1. org.apache.commons.logging
      1. 1.1.1. org.apache.commons.logging.LogFactory
    2. 1.2. getLog中的参数测试
      1. 1.2.1. 测试所用日志maven依赖
      2. 1.2.2. 测试类
      3. 1.2.3. log4j的配置文件
      4. 1.2.4. 测试方法1
      5. 1.2.5. 测试方法2
      6. 1.2.6. 测试方法3
      7. 1.2.7. 测试1,2,3方法总结
      8. 1.2.8. 测试方法4
      9. 1.2.9. 测试方法5
      10. 1.2.10. 测试4,5方法总结
  2. 2. log4j2
    1. 2.1. 测试
    2. 2.2. log4j2配置说明