2018年06月03日 14:45:22 贤和兄 阅读数:15425

从图中不难看出,在线程数为 2~16 之间,混合使用同步和异步的logger来打印日志,性能是最好的
1、选择Log4j2的理由是啥,为啥不用spring boot 默认的?
| 优化 | 说明 |
|---|---|
| 执行速度 | Log4j 2.x 相对于 Log4j 1.x 和 Logback来说,具有更快的执行速度。一方面由于 重写了内部的实现,在某些特定的场景上面,甚至可以比之前的速度快上10倍。比如内部的消息队列采用了ArrayBlockingQueue,相对于原始的ArrayList和锁操作来说,管程类的消息队列拥有更好地性能。同时所需的内存更加少。这是因为Log4j 2.x 采用占位符的形式打印日志(类似于Slf4j门面日志的形式),会先判断一下日志的等级,然后再拼接要打印的内容。另一方面由于Log4j 2.x 充分利用Java 5的并发特性(主要是使用了一些concurrent包下锁),使得性能得到一定的改善,而Log4j 1.x和Logback很多地方还是用的重锁。 |
| 异步性能 | Asynchronous Loggers是Log4j2新增的日志器,异步日志器在其内部实现采用了LMAX Disruptor(一个无锁的线程间通信库)技术,Disruptor主要通过环形数组结构、元素位置定位和精巧的无锁设计(CAS)实现了在高并发情形下的高性能。而且Log4j 2.x中Asynchronous Appenders作为Asynchronous Loggers工作的一部分,效果进行了增强。每次写入磁盘时,都会进行flush操作,效果和配置“immediateFlush=true”一样。该异步Appender内部采用ArrayBlockingQueue的方式。RandomAccessFileAppender采用ByteBuffer+RandomAccessFile替代了BufferedOutputStream,官方给出的测试数据是它将速度提升了20-200%。 |
| 自动加载配置文件 | Log4j 2.x 和Logback都新增了自动加载日志配置文件的功能,又与Logback不同,配置发生改变时不会丢失任何日志事件。当Log4j 2.x中配置发生改变时,如果还有日志事件尚未处理,Log4j 2会继续处理,当处理完成后,Logger会重新指向新配置的LoggerConfig对象,并且删除无用的对象。 |
| 死锁问题的解决 | 在Log4j 1.x中同步写日志的时候,在高并发情况下出现死锁导致cpu使用率异常飙升。其中的原因是当一个进程写日志的时候需要获取到Logger和Appender。org.apache.log4j.Logger类继承于org.apache.log4j.Category、Appender继承于org.apache.log4j.AppenderSkeleton。通过Log4j 1.x中Category源码和Appender源码可以知道,当多线程并发时,可能会因为相互持有Logger和Appender发生死锁。 而在log4j 2.x中充分利用Java5的并发支持,并且以最低级别执行锁定。 |
2、Maven 依赖 pom.xml配置
去掉默认日志,加载别的日志,spring boot提供log4j2的解决方案,如下配置
-
<!-- 包含 mvc,aop 等jar资源 --> -
<dependency> -
<groupId>org.springframework.boot</groupId> -
<artifactId>spring-boot-starter-web</artifactId> -
<exclusions> -
<!-- 切换log4j2日志读取 --> -
<exclusion> -
<groupId>org.springframework.boot</groupId> -
<artifactId>spring-boot-starter-logging</artifactId> -
</exclusion> -
</exclusions> -
</dependency>
然后添加如下两个依赖
-
<!-- 配置 log4j2 --> -
<dependency> -
<groupId>org.springframework.boot</groupId> -
<artifactId>spring-boot-starter-log4j2</artifactId> -
</dependency> -
<!-- 加上这个才能辨认到log4j2.yml文件 --> -
<dependency> -
<groupId>com.fasterxml.jackson.dataformat</groupId> -
<artifactId>jackson-dataformat-yaml</artifactId> -
</dependency>
3、配置文件添加log4j2.yml
文件存放resource目录下
-
# 共有8个级别,按照从低到高为:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF。 -
Configuration: -
status: warn -
monitorInterval: 30 -
Properties: # 定义全局变量 -
Property: # 缺省配置(用于开发环境)。其他环境需要在VM参数中指定,如下: -
#测试:-Dlog.level.console=warn -Dlog.level.xjj=trace -
#生产:-Dlog.level.console=warn -Dlog.level.xjj=info -
- name: log.level.console -
value: info -
- name: log.path -
value: log -
- name: project.name -
value: opendoc -
- name: log.pattern -
value: "%d{yyyy-MM-dd HH:mm:ss.SSS} -%5p ${PID:-} [%15.15t] %-30.30C{1.} : %m%n" -
Appenders: -
Console: #输出到控制台 -
name: CONSOLE -
target: SYSTEM_OUT -
PatternLayout: -
pattern: ${log.pattern} -
# 启动日志 -
RollingFile: -
- name: ROLLING_FILE -
fileName: ${log.path}/${project.name}.log -
filePattern: "${log.path}/historyRunLog/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz" -
PatternLayout: -
pattern: ${log.pattern} -
Filters: -
# 一定要先去除不接受的日志级别,然后获取需要接受的日志级别 -
ThresholdFilter: -
- level: error -
onMatch: DENY -
onMismatch: NEUTRAL -
- level: info -
onMatch: ACCEPT -
onMismatch: DENY -
Policies: -
TimeBasedTriggeringPolicy: # 按天分类 -
modulate: true -
interval: 1 -
DefaultRolloverStrategy: # 文件最多100个 -
max: 100 -
# 平台日志 -
- name: PLATFORM_ROLLING_FILE -
ignoreExceptions: false -
fileName: ${log.path}/platform/${project.name}_platform.log -
filePattern: "${log.path}/platform/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz" -
PatternLayout: -
pattern: ${log.pattern} -
Policies: -
TimeBasedTriggeringPolicy: # 按天分类 -
modulate: true -
interval: 1 -
DefaultRolloverStrategy: # 文件最多100个 -
max: 100 -
# 业务日志 -
- name: BUSSINESS_ROLLING_FILE -
ignoreExceptions: false -
fileName: ${log.path}/bussiness/${project.name}_bussiness.log -
filePattern: "${log.path}/bussiness/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz" -
PatternLayout: -
pattern: ${log.pattern} -
Policies: -
TimeBasedTriggeringPolicy: # 按天分类 -
modulate: true -
interval: 1 -
DefaultRolloverStrategy: # 文件最多100个 -
max: 100 -
# 错误日志 -
- name: EXCEPTION_ROLLING_FILE -
ignoreExceptions: false -
fileName: ${log.path}/exception/${project.name}_exception.log -
filePattern: "${log.path}/exception/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz" -
ThresholdFilter: -
level: error -
onMatch: ACCEPT -
onMismatch: DENY -
PatternLayout: -
pattern: ${log.pattern} -
Policies: -
TimeBasedTriggeringPolicy: # 按天分类 -
modulate: true -
interval: 1 -
DefaultRolloverStrategy: # 文件最多100个 -
max: 100 -
# DB 日志 -
- name: DB_ROLLING_FILE -
ignoreExceptions: false -
fileName: ${log.path}/db/${project.name}_db.log -
filePattern: "${log.path}/db/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz" -
PatternLayout: -
pattern: ${log.pattern} -
Policies: -
TimeBasedTriggeringPolicy: # 按天分类 -
modulate: true -
interval: 1 -
DefaultRolloverStrategy: # 文件最多100个 -
max: 100 -
Loggers: -
Root: -
level: info -
AppenderRef: -
- ref: CONSOLE -
- ref: ROLLING_FILE -
- ref: EXCEPTION_ROLLING_FILE -
Logger: -
- name: platform -
level: info -
additivity: false -
AppenderRef: -
- ref: CONSOLE -
- ref: PLATFORM_ROLLING_FILE -
- name: bussiness -
level: info -
additivity: false -
AppenderRef: -
- ref: BUSSINESS_ROLLING_FILE -
- name: exception -
level: debug -
additivity: true -
AppenderRef: -
- ref: EXCEPTION_ROLLING_FILE -
- name: db -
level: info -
additivity: false -
AppenderRef: -
- ref: DB_ROLLING_FILE -
# 监听具体包下面的日志 -
# Logger: # 为com.xjj包配置特殊的Log级别,方便调试 -
# - name: com.xjj -
# additivity: false -
# level: ${sys:log.level.xjj} -
# AppenderRef: -
# - ref: CONSOLE -
# - ref: ROLLING_FILE
4、引入配置文件
在application.yml引入
-
logging: -
config: classpath:log4j2.yml
5、不同日志工具类util编辑
由于配置了4个文件存放不同日志,分别为平台日志(${project.name}_platform.log)、 业务日志(${project.name}_bussiness.log)、错误日志(${project.name}_exception.log)、DB 日志(${project.name}_db.log),文件夹外面为运行日志,不同文件日志级别不一样,因此程序员在开发时候需要注意引入不同日志,也就是说开发出现的日志,程序员可以进行分类,分别调用公共方法即可。公共类编辑如下;
-
package com.open.util; -
/** -
* 本地日志枚举 -
* @author Administrator -
* -
*/ -
public enum LogEnum { -
BUSSINESS("bussiness"), -
PLATFORM("platform"), -
DB("db"), -
EXCEPTION("exception"), -
; -
private String category; -
LogEnum(String category) { -
this.category = category; -
} -
public String getCategory() { -
return category; -
} -
public void setCategory(String category) { -
this.category = category; -
} -
}
-
package com.open.util; -
import org.slf4j.Logger; -
import org.slf4j.LoggerFactory; -
/** -
* 本地日志参考类 -
* @author Administrator -
* -
*/ -
public class LogUtils { -
/** -
* 获取业务日志logger -
* -
* @return -
*/ -
public static Logger getBussinessLogger() { -
return LoggerFactory.getLogger(LogEnum.BUSSINESS.getCategory()); -
} -
/** -
* 获取平台日志logger -
* -
* @return -
*/ -
public static Logger getPlatformLogger() { -
return LoggerFactory.getLogger(LogEnum.PLATFORM.getCategory()); -
} -
/** -
* 获取数据库日志logger -
* -
* @return -
*/ -
public static Logger getDBLogger() { -
return LoggerFactory.getLogger(LogEnum.DB.getCategory()); -
} -
/** -
* 获取异常日志logger -
* -
* @return -
*/ -
public static Logger getExceptionLogger() { -
return LoggerFactory.getLogger(LogEnum.EXCEPTION.getCategory()); -
} -
}
具体调用如下:
-
@GetMapping("/helloworld") -
public String helloworld() throws Exception{ -
Logger log = LogUtils.getExceptionLogger(); -
Logger log1 = LogUtils.getBussinessLogger(); -
Logger log2 = LogUtils.getDBLogger(); -
userService.queryUser(); -
log.error("getExceptionLogger===日志测试"); -
log1.info("getBussinessLogger===日志测试"); -
log2.debug("getDBLogger===日志测试"); -
return "helloworld"; -
}
生成日志目录如下

Log4j2在Spring Boot中的高级应用
本文深入探讨了Log4j2在Spring Boot项目中的配置与优化,包括性能提升、异步日志处理、自动加载配置、解决死锁问题及日志分类输出。通过对比Log4j1.x和Logback,展示了Log4j2的优越性,并提供了详细的Maven依赖、log4j2.yml配置示例及日志工具类的编写指导。
1427

被折叠的 条评论
为什么被折叠?



