1 Log4j入门
1.1 Loggers
1.2 Appenders
![](https://i-blog.csdnimg.cn/blog_migrate/394968512987502ee9944996d7f13765.png)
1.3 Layouts
![](https://i-blog.csdnimg.cn/blog_migrate/81b6077e633ade58c0e0c22059694b98.png)
%m 输出代码中指定的日志信息 %p 输出优先级,及 DEBUG、INFO 等 %n 换行符(Windows平台的换行符为 "\n",Unix 平台为 "\n") %r 输出自应用启动到输出该 log 信息耗费的毫秒数 %c 输出打印语句所属的类的全名 %t 输出产生该日志的线程全名 %d 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy-MM-dd HH:mm:ss} %l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:10) %F 输出日志消息产生时所在的文件名称 %L 输出代码中的行号 %% 输出一个 "%" 字符 % ctFL 相当于 l 就可以包含前几个输出格式 #可以在 % 与字符之间加上修饰符来控制最小宽度、最大宽度和文本的对其方式。如: %5c 输出category名称,最小宽度是5,category<5,默认的情况下右对齐 %-5c 输出category名称,最小宽度是5,category<5,"-"号指定左对齐,会有空格 %.5c 输出category名称,最大宽度是5,category>5,就会将左边多出的字符截掉,<5不会有空格 %20.30c category名称<20补空格,并且右对齐,>30字符,就从左边交远销出的字符截掉
2 入门案例
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
3. 代码
public class Log4jTest {
@Test
public void testQuick() throws Exception {
// 初始化系统配置,不需要配置文件, 有配置文件需要注释掉
BasicConfigurator.configure();
// 创建日志记录器对象
Logger logger = Logger.getLogger(Log4jTest.class);
// 日志记录输出
logger.info("hello log4j");
// 日志级别
logger.fatal("fatal"); // 严重错误,一般会造成系统崩溃和终止运行
logger.error("error"); // 错误信息,但不会影响系统运行
logger.warn("warn"); // 警告信息,可能会发生问题
logger.info("info"); // 程序运行信息,数据库的连接、网络、IO操作等
logger.debug("debug"); // 调试信息,一般在开发阶段使用,记录程序的变量、参数等
logger.trace("trace"); // 追踪信息,记录程序的所有流程信息
}
}
4. 配置文件 resources 下面名称为 log4j.properties
# 指定 RootLogger 顶级父元素默认配置信息
# 指定日志级别=trace,使用的 apeender 为=console(console可自定义名称)
log4j.rootLogger=INFO,console,file
# 自定义 logger (继承rootLogger) 对象设置 (日志级别会覆盖rootLogger,appender方式都会起作用)
log4j.logger.com.csi.log = error,mydailyFile
# 指定控制台日志输出的 appender
log4j.appender.console=org.apache.log4j.ConsoleAppender
# 指定消息格式 layout
log4j.appender.console.layout=org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
# 日志文件输出的 appender 对象 file 可自定义名
log4j.appender.file = org.apache.log4j.FileAppender
log4j.appender.file.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.file.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
# 指定日志文件保存路径
log4j.appender.file.file = C:/Users/Public/Desktop/logs/log4j.log
# 指定日志文件保存路径
log4j.appender.file.encoding = UTF-8
![](https://i-blog.csdnimg.cn/blog_migrate/e93cdc2d86b656c11f7b1cc6e19d65a5.png)
2.1 FileAppender 的两个子类
FileAppender 默认日志追加到日志文件中,防止过大可进行文件拆分和时间拆分
# 按照文件大小 拆分的 appender 对象 FileAppender 的子类 RollingFileAppender
# 日志文件输出的 appender 对象
log4j.appender.rollingFile = org.apache.log4j.RollingFileAppender
# 指定消息格式 layout
log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.rollingFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
# 指定日志文件保存路径
log4j.appender.rollingFile.file = C:/Users/15121262356/Desktop/logs/log4j.log
# 指定日志文件的字符集
log4j.appender.rollingFile.encoding = UTF-8
# 指定日志文件内容的大小
log4j.appender.rollingFile.maxFileSize = 1MB
# 指定日志文件的数量 (超过10个 按时间覆盖 比较久远的就给覆盖了)
log4j.appender.rollingFile.maxBackupIndex = 10
# 按照时间规则拆分的 appender 对象
log4j.appender.mydailyFile = org.apache.log4j.DailyRollingFileAppender
# 指定消息格式 layout
log4j.appender.mydailyFile.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.mydailyFile.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
# 指定日志文件保存路径
log4j.appender.mydailyFile.file = C:/Users/15121262356/Desktop/logs/log4j.log
# 指定日志文件的字符集
log4j.appender.mydailyFile.encoding = UTF-8
# 指定日期拆分规则
log4j.appender.mydailyFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss
2.2 将日志插入mysql
CREATE TABLE `log` (
`log_id` int(11) NOT NULL AUTO_INCREMENT,
`project_name` varchar(255) DEFAULT NULL COMMENT '目项名',
`create_date` varchar(255) DEFAULT NULL COMMENT '创建时间',
`level` varchar(255) DEFAULT NULL COMMENT '优先级',
`category` varchar(255) DEFAULT NULL COMMENT '所在类的全名',
`file_name` varchar(255) DEFAULT NULL COMMENT '输出日志消息产生时所在的文件名称 ',
`thread_name` varchar(255) DEFAULT NULL COMMENT '日志事件的线程名',
`line` varchar(255) DEFAULT NULL COMMENT '号行',
`all_category` varchar(255) DEFAULT NULL COMMENT '日志事件的发生位置',
`message` varchar(4000) DEFAULT NULL COMMENT '输出代码中指定的消息',
PRIMARY KEY (`log_id`)
);
# 指定 RootLogger 顶级父元素默认配置信息 使用哪个后面加上哪一个
# 指定日志级别=INFO,使用的 apeender 为=console(console可自定义名称)
log4j.rootLogger=INFO,console,myDB
# 自定义 logger (继承rootLogger) 对象设置 (日志级别会覆盖rootLogger,appender方式都会起作用)
log4j.logger.com.csi.log = error,mydailyFile
# 指定控制台日志输出的 appender
log4j.appender.console=org.apache.log4j.ConsoleAppender
# 指定消息格式 layout
log4j.appender.console.layout=org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.console.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
# 日志文件输出的 appender 对象 file 可自定义名
log4j.appender.file = org.apache.log4j.FileAppender
log4j.appender.file.layout = org.apache.log4j.PatternLayout
# 指定消息格式的内容
log4j.appender.file.layout.conversionPattern = [%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
# 指定日志文件保存路径
log4j.appender.file.file = C:/Users/Public/Desktop/logs/log4j.log
# 指定日志文件保存路径
log4j.appender.file.encoding = UTF-8
#mysql
log4j.appender.myDB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.myDB.layout=org.apache.log4j.PatternLayout
log4j.appender.myDB.Driver=com.mysql.cj.jdbc.Driver
log4j.appender.myDB.URL=jdbc:mysql://localhost:3306/zk?serverTimezone=Asia/Shanghai
log4j.appender.myDB.User=root
log4j.appender.myDB.Password=root
log4j.appender.myDB.Sql=INSERT log(project_name,create_date,\
level,category,file_name,thread_name,line,all_category,message) \
values('zk','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')
3. 自定义Logger
# 自定义 logger (继承rootLogger) 对象设置 (日志级别会覆盖rootLogger,appender方式都会起作用)
log4j.logger.com.csi.log = error,mydailyFile
2 JCL
全称为Jakarta Commons Logging,是Apache提供的一个通用日志API。
它是为 "所有的Java日志实现"提供一个统一的接口,它自身也提供一个日志的实现,但是功能非常常弱(SimpleLog)。所以一般不会单独使用它。他允许开发人员使用不同的具体日志实现工具: Log4j, Jdk自带的日志(JUL)。
JCL 有两个基本的抽象类:Log(基本记录器) 和LogFactory(负责创建Log实例)。
2.1 入门案例
引入依赖
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
public void test() throws Exception {
// 创建日志对象
Log log = LogFactory.getLog(JULTest.class);
// 日志记录输出
log.fatal("fatal");
log.error("error");
log.warn("warn");
log.info("info");
log.debug("debug");
}
默认使用JDK14 默认的日志输出。
当加入log4j的依赖后,配置文件就使用的是log4j输出
2.2 为什么使用日志门面
- 面向接口开发,不再依赖具体的实现类。减少代码的耦合
- 项目通过导入不同的日志实现类,可以灵活的切换日志框架
- 统一API,方便开发者学习和使用
- 统一配置便于项目日志的管理
2.3 jcl 经典
经典白学已经被淘汰了
3. 日志门面
![](https://i-blog.csdnimg.cn/blog_migrate/f7c16307a11b7a4d235a6dedaf54d62b.png)
日志框架出现的历史顺序:
4. SLF4J的使用
4.1 SLF4J入门
<!--slf4j core 使用slf4j必須添加-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.27</version>
</dependency>
<!--slf4j 自带的简单日志实现 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.27</version>
</dependency>
2. demo
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Slf4jTest {
public static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);
@Test
public void test1(){
// 日志输出
LOGGER.error("error");
LOGGER.warn("wring");
LOGGER.info("info"); // 默认级别
LOGGER.debug("debug");
LOGGER.trace("trace");
// 可以使用占位符
String name = "宝竹";
LOGGER.info("hello: {}",name);
try {
int i = 10 / 0;
}catch (Exception e){
// e.printStackTrace();
LOGGER.info("出现异常了 啊 a a");
}
}
}
4.2 绑定日志的实现(Binding)
通过maven引入常见的日志实现框架: (日志实现需要要导入一个即可)
<!--slf4j 日志门面 使用slf4j必须添加-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<!--slf4j 内置的简单实现-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<!--绑定logback 日志实现-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!--sl4f-nop slf4j日志开关 导入后将不会开启日志输出-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.25</version>
</dependency>
<!--绑定log4j-->
<!--绑定log4j的日志实现需要导入适配器 slf4j-log4j12-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.29</version>
</dependency>
<!--log4j日志实现-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--绑定jul-->
<!--绑定jul 日志实现 需要导入适配器 slf4j-jdk14-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.5.6</version>
</dependency>
要切换日志框架,只需替换类路径上的slf4j绑定。例如,要从java.util.logging切换到log4j,只需将slf4j-jdk14-1.7.27.jar替换为slf4j-log4j12-1.7.27.jar即可。
SLF4J不依赖于任何特殊的类装载。实际上,每个SLF4J绑定在编译时都是硬连线的, 以使用一个且只有一个特定的日志记录框架。例如,slf4j-log4j12-1.7.27.jar绑定在编译时绑定以使用log4j。在您的代码中,除了slf4j-api-1.7.27.jar之外,您只需将您选择的一个且只有一个绑定放到相应的类路径位置。不要在类路径上放置多个绑定。以下是一般概念的图解说明。
2.3 桥接旧的日志框架(Bridging)
假设我们原本项目用的 log4j
<!--log4j日志实现-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
import org.apache.log4j.Logger;
import org.junit.Test;
public class Log4jTest1 {
public static Logger LOGGER = Logger.getLogger(Log4jTest1.class);
@Test
public void test1(){ // 测试桥接
LOGGER.info("hello log4j");
}
}
当我们想换掉 log4j 使用日志门面绑定logback 日志实现,那么上述代码就会报错。
当使用桥接器后 ,上面代码就不会报错了
<!-- 1,先去除之前老的日志框架的依赖-->
<!-- <dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
-->
<!-- 2. 添加SLF4J提供的桥接组件-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
<!-- 3. 为项目添加SLF4J的具体实现-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!--绑定logback 日志实现-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
迁移的方式:
如果我们要使用SLF4J的桥接器,替换原有的日志框架,那么我们需要做的第一件事情,就是删除掉原有项目中的日志框架的依赖。然后替换成SLF4J提供的桥接器。
SLF4J提供的桥接器:
<!-- log4j桥接器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.27</version>
</dependency>
<!-- jul 桥接器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.27</version>
</dependency>
<!--jcl 桥接器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.27</version>
</dependency>
注意
- jcl-over-slf4j.jar和 slf4j-jcl.jar不能同时部署。前一个jar文件将导致JCL将日志系统的选择委托给 SLF4J,后一个jar文件将导致SLF4J将日志系统的选择委托给JCL,从而导致无限循环。
- log4j-over-slf4j.jar和slf4j-log4j12.jar不能同时出现 (桥接器和适配器)
- jul-to-slf4j.jar和slf4j-jdk14.jar不能同时出现
- 所有的桥接都只对Logger日志记录器对象有效,如果程序中调用了内部的配置类或者是Appender,Filter等对象,将无法产生效果
当日志门面slf4j 桥接器 适配器 log4j 依赖同时存在,运行会报栈溢出错误
开始的时候使用log4j 具体实现输出,后面改造为 日志门面加上 其他日志输出模式。就需要加上 桥接器。log4j的功能被取消。然后日志门面调用适配器,适配器又调用桥接器。然后就死循环了。
5. Logback
5.1 入门
Logback是由log4j创始人设计的另一个开源日志组件,性能比log4j要好。官方网站:https://logback.qos.ch/index.html
Logback主要分为三个模块:
logback-core:其它两个模块的基础模块
logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API
logback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能
入门案例: 导入依赖
<!--slf4j 日志门面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!--logback 日志实现 引入了 classic也引入了logback-core 他们有依赖关系-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogBackTest {
public static final Logger LOGGER = LoggerFactory.getLogger(LogBackTest.class);
@Test
public void test1(){
// 日志输出
LOGGER.error("error");
LOGGER.warn("wring");
LOGGER.info("info");
LOGGER.debug("debug");// 默认级别
LOGGER.trace("trace");
}
5.2 logback配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--日志输出格式:
%-5level
%d{yyyy-MM-dd HH:mm:ss.SSS}日期
%c类的完整名称
%M为method
%L为行号
%thread线程名称
%m或者%msg为信息
%n换行
格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度
%m或者%msg为日志消息,%n是换行符
-->
<!-- name 自定义名称-->
<property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n"></property>
<!--定义日志文件保存路径属性-->
<property name="my_dir" value="C:/Users/15121262356/Desktop/logs"></property>
<!--控制台日志输出的 appender-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--控制输出流对象 默认 System.out 改为 System.err :输出变成红色字体-->
<target>System.err</target>
<!--日志消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender>
<!--日志文件输出的 appender : 输出到指定文件 -->
<appender name="my_file" class="ch.qos.logback.core.FileAppender">
<!--日志文件保存路径-->
<file>${my_dir}/logback.log</file>
<!--日志消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender>
<!--html 格式日志文件输出 appender :输出到指定文件 -->
<appender name="htmlFile" class="ch.qos.logback.core.FileAppender">
<!--日志文件保存路径-->
<file>${my_dir}/logback.html</file>
<!--html 消息格式配置-->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%-5level%d{yyyy-MM-dd HH:mm:ss}%c%M%L%thread%m</pattern>
</layout>
</encoder>
</appender>
<!--root logger 配置 : 输出级别 和 输出到哪里-->
<root level="ALL">
<appender-ref ref="console"/>
<appender-ref ref="my_file"/>
<appender-ref ref="htmlFile"/>
</root>
</configuration>
配置进阶
过滤器: 配置到appender当中,error 通过,其余的拦截。
异步日志: 提高性能,后续输出到日志文件当中。
自定义日志: com.csi包 下面的日志遵循自己的日志规则,additivity="false" 表示不继承父类的输出规则,只在控制台输出。不会在文件当中输出了。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- name 自定义名称-->
<property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n"></property>
<!--定义日志文件保存路径属性-->
<property name="my_dir" value="C:/Users/15121262356/Desktop/logs"></property>
<!--控制台日志输出的 appender-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--控制输出流对象 默认 System.out 改为 System.err :输出变成红色字体-->
<target>System.err</target>
<!--日志消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender>
<!--日志拆分和归档压缩的 appender 对象-->
<appender name="my_rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件保存路径-->
<file>${my_dir}/roll_logback.log</file>
<!--日志消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
<!--指定拆分规则-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--按照时间和压缩格式声明拆分的文件名 : gz 是压缩包格式-->
<fileNamePattern>${my_dir}/rolling.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern>
<!--按照文件大小拆分-->
<maxFileSize>1MB</maxFileSize>
</rollingPolicy>
<!--日志级别过滤器-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--日志过滤规则 :error通过,其他的拦截-->
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--异步日志 : 提高性能后续再生成日志-->
<appender name="my_async" class="ch.qos.logback.classic.AsyncAppender">
<!--指定某个具体的 appender-->
<appender-ref ref="my_rollFile"/>
</appender>
<!--自定义 looger 对象
additivity="false" 自定义 logger 对象是否继承 rootLogger
-->
<logger name="com.csi" level="info" additivity="false">
<appender-ref ref="console"/>
</logger>
<!--root logger 配置 : 输出级别 和 输出到哪里-->
<root level="ALL">
<appender-ref ref="console"/>
<!-- <appender-ref ref="my_file"/>-->
<appender-ref ref="my_async"/>
</root>
</configuration>
6. log4j2的使用
- 异常处理,在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。
- 性能提升, log4j2相较于log4j 和logback都具有很明显的性能提升,后面会有官方测试的数据。
- 自动重载配置,参考了logback的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产上可以动态的修改日志的级别而不需要重启应用。
- 无垃圾机制,log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的jvm gc。
6.1 Log4j2入门
<!-- Log4j2 门面API-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>
<!-- Log4j2 日志实现 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2Test {
// 定义日志记录器对象
public static final Logger LOGGER = LogManager.getLogger(Log4j2Test.class);
// 快速入门
@Test
public void testQuick()throws Exception{
// 日志消息输出
LOGGER.fatal("fatal");
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("inf");
LOGGER.debug("debug");
LOGGER.trace("trace");
}
}
<!-- Log4j2 门面API-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>
<!-- Log4j2 日志实现 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
<!--使用slf4j作为日志的门面,使用log4j2来记录日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<!--为slf4j绑定日志实现 log4j2的适配器 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.10.0</version>
</dependency>
6.2 Log4j2配置
<?xml version="1.0" encoding="UTF-8"?>
<!-- status="warn" 日志框架本身的输出日志级别
monitorInterval="5" 自动加载配置文件的间隔时间,不低于 5 秒 -->
<Configuration status="debug" monitorInterval="5">
<!--集中配置属性进行管理 使用时通过:${name} -->
<properties>
<property name="LOG_HOME">C:/Users/15121262356/Desktop/logs</property>
</properties>
<!--日志处理-->
<Appenders>
<!--控制台输出 appender-->
<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" />
</Console>
<!--日志文件输出 appender-->
<File name="file" fileName="${LOG_HOME}/myfile.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />
</File>
<!--<Async name="Async">-->
<!--<AppenderRef ref="file"/>-->
<!--</Async>-->
<!--使用随机读写流的日志文件输出 appender,性能提高-->
<RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />
</RandomAccessFile>
<!--按照一定规则拆分的日志文件的 appender-->
<RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log"
filePattern="/logs/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log">
<!--日志级别过滤器-->
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
<!--日志消息格式-->
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %msg%n" />
<Policies>
<!--在系统启动时,出发拆分规则,生产一个新的日志文件-->
<OnStartupTriggeringPolicy />
<!--按照文件大小拆分,10MB -->
<SizeBasedTriggeringPolicy size="10 MB" />
<!--按照时间节点拆分,规则根据filePattern定义的-->
<TimeBasedTriggeringPolicy />
</Policies>
<!--在同一个目录下,文件的个数限定为 30 个,超过进行覆盖-->
<DefaultRolloverStrategy max="30" />
</RollingFile>
</Appenders>
<!--logger 定义-->
<Loggers>
<!--自定义异步 logger 对象 includeLocation="false" 关闭日志记录的行号信息
additivity="false" 不在继承 rootlogger 对象 -->
<AsyncLogger name="com.itheima" level="trace" includeLocation="false" additivity="false">
<AppenderRef ref="Console"/>
</AsyncLogger>
<!--使用 rootLogger 配置 日志级别 level="trace"-->
<Root level="trace">
<!--指定日志使用的处理器-->
<AppenderRef ref="Console" />
<!--使用异步 appender-->
<!-- <AppenderRef ref="Async" />-->
</Root>
</Loggers>
</Configuration>
6.3 Log4j2异步日志
- 同步日志 (主线程日志输出需要执行完这么多步骤才可以往下执行,会严重影响性能)
- 异步日志 (主线程创建一个Logger对象后,生成logEvent后 就交给阻塞队列了,主线程就不管了可以执行其他操作了。log4j2 开启新的线程来执行接下来的操作不会影响主线程)
<!--异步日志依赖-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.4</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<properties>
<property name="LOG_HOME">D:/logs</property>
</properties>
<Appenders>
<File name="file" fileName="${LOG_HOME}/myfile.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
异步日志 导入依赖的方式
<Async name="Async">
<AppenderRef ref="file"/>
</Async>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Async"/>
</Root>
</Loggers>
</Configuration>
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
混合异步:就是,你可以在应用中同时使用同步日志和异步日志,这使得日志的配置方式更加灵活。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<properties>
<property name="LOG_HOME">D:/logs</property>
</properties>
<Appenders>
<File name="file" fileName="${LOG_HOME}/myfile.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
<Async name="Async">
<AppenderRef ref="file"/>
</Async>
</Appenders>
<Loggers>
<!--com.chen 日志是异步的,root日志是同步的。-->
<!--自定义异步 logger 对象 includeLocation="false"
关闭日志记录的行号信息(因为行号信息可能影响异步日志性能)
additivity="false" 不在继承 rootlogger 对象 -->
<AsyncLogger name="com.csi" level="trace"
includeLocation="false" additivity="false">
<AppenderRef ref="file"/>
</AsyncLogger>
<Root level="info" includeLocation="true">
<AppenderRef ref="file"/>
</Root>
</Loggers>
</Configuration>
6.4 Log4j2的性能
Log4j 2.6没有分配临时对象:0(零)垃圾回收。
- log4j2.enableThreadlocals - 如果“true”(非Web应用程序的默认值)对象存储在ThreadLocal字段中并重新使用,否则将为每个日志事件创建新对象。
- log4j2.enableDirectEncoders - 如果将“true”(默认)日志事件转换为文本,则将此文本转换 为字节而不创建临时对象。注意: 由于共享缓冲区上的同步,在此模式下多线程应用程序的同步日志记录性能可能更差。如果您的应用程序是多线程的并且日志记录性能很重要,请考虑使用异步记录器。
7. SpringBoot中的日志使用
7.1 SpringBoot中的日志设计
<dependency>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
![](https://i-blog.csdnimg.cn/blog_migrate/6b2e302a408f1428f3b73a45f734dc01.png)
7.2 SpringBoot日志使用
@SpringBootTest
class SpringbootLogApplicationTests {
//记录器
public static final Logger LOGGER =
LoggerFactory.getLogger(SpringbootLogApplicationTests.class);
@Test
public void contextLoads() {
// 打印日志信息
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info"); // 默认日志级别
LOGGER.debug("debug");
LOGGER.trace("trace");
// 使用 lo4j2 使用桥接器切换为 slf4j 门面和 logback 日志实现
org.apache.logging.log4j.Logger logger = LogManager.getLogger(SpringbootLogApplicationTests.class);
logger.info("log4j2 info");
}
}
# 指定自定义 logger 对象日志级别
logging.level.com.csi=trace
# 指定控制台输出消息格式
logging.pattern.console=[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread]===== %msg %n
# 指定存放日志文件的具体路径
# logging.file=/logs/springboot.log
# 指定日志文件存放的目录,默认的文件名 spring.log
logging.file.path=/logs/springboot/
# 指定日志文件消息格式
logging.pattern.file=[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c [%thread]===== %msg %n
# 指定项目使用的具体环境
spring.profiles.active=dev
logback.xml:直接就被日志框架识别了
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] -------- %m %n"></property>
<!--控制台日志输出的 appender-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--控制输出流对象 默认 System.out 改为 System.err-->
<target>System.err</target>
<!--日志消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<springProfile name="dev">
<pattern>${pattern}</pattern>
</springProfile>
<springProfile name="pro">
<pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] xxxxxxxx %m %n</pattern>
</springProfile>
</encoder>
</appender>
<!--自定义 looger 对象
additivity="false" 自定义 logger 对象是否继承 rootLogger-->
<logger name="com.csi" level="info" additivity="false">
<appender-ref ref="console"/>
</logger>
</configuration>
spring.profiles.active=dev
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--排除logback-->
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>