网站建设的英文翻译,怎么做网站策划,wap端网站建设,专注徐州网站开发1. JAVA日志框架
1.1 为什么程序需要记录日志
我们不可能实时的24小时对系统进行人工监控#xff0c;那么如果程序出现异常错误时要如何排查呢#xff1f;并且系统在运行时做了哪些事情我们又从何得知呢#xff1f;这个时候日志这个概念就出现了#xff0c;日志的出现对系…1. JAVA日志框架
1.1 为什么程序需要记录日志
我们不可能实时的24小时对系统进行人工监控那么如果程序出现异常错误时要如何排查呢并且系统在运行时做了哪些事情我们又从何得知呢这个时候日志这个概念就出现了日志的出现对系统监控和异常分析起着至关重要的作用。 就拿java来说在早期的日志都是通过System.out.println()进行记录的但是这种方式不便于管理所以apache最先开发了首个日志框架log4j; 为日志框架奠定了基础。
1.2 为什么要用日志框架
因为软件系统发展到今天已经很复杂了特别是服务器端软件涉及到的知识内容问题太多。在某 些方面使用别人成熟的框架就相当于让别人帮你完成一些基础工作你只需要集中精力完成系统的业 务逻辑设计。而且框架一般是成熟稳健的他可以处理系统很多细节问题比如事务处理安全 性数据流控制等问题。还有框架一般都经过很多人使用所以结构很好所以扩展性也很好而且它 是不断升级的你可以直接享受别人升级代码带来的好处。
1.3 现有的日志框架
日志实现 log4j老牌日志框架apache 旗下JULjava.util.loggingjava自带的日志框架适合小型项目logback目前比较火的框架spring2.0默认使用logback日志log4j2log4j升级版目前最好的日志实现技术 日志门面接口 JCLjakarta commons Loggingapache旗下slf4j (simple logging facade for java)目前比较火的
日志框架出现的历史顺序为 log4j → JUL → JCL → SLF4J → logback → log4j2
2. JUL学习 java.util.logging
JUL全称Java util Logging是java原生的日志框架使用时不需要另外引用第三方类库相对其他日志框 架使用方便学习简单能够在小型应用中灵活使用。
2.1 JUL入门
2.1.1 架构介绍 Loggers被称为记录器应用程序通过获取Logger对象调用其API来来发布日志信息。Logger 通常时应用程序访问日志系统的入口程序。Appenders也被称为Handlers每个Logger都会关联一组HandlersLogger会将日志交给关联 Handlers处理由Handlers负责将日志做记录。Handlers在此是一个抽象其具体的实现决定了 日志记录的位置可以是控制台、文件、网络上的其他日志服务或操作系统日志等。Layouts也被称为Formatters它负责对日志事件中的数据进行转换和格式化。Layouts决定了 数据在一条日志记录中的最终形式。Level每条日志消息都有一个关联的日志级别。该级别粗略指导了日志消息的重要性和紧迫我 可以将Level和LoggersAppenders做关联以便于我们过滤消息。Filters过滤器根据需要定制哪些信息会被记录哪些信息会被放过。
总结一下就是 用户使用Logger来进行日志记录Logger持有若干个Handler日志的输出操作是由Handler完成的。 在Handler在输出日志前会经过Filter的过滤判断哪些日志级别过滤放行哪些拦截Handler会将日 志内容输出到指定位置日志文件、控制台等。Handler在输出日志时会使用Layout将输出内容进 行排版。
2.1.2 入门案例
public class JULTest {Testpublic void testQuick() throws Exception {// 1.创建日志记录器对象Logger logger Logger.getLogger(com.itheima.log.JULTest);// 2.日志记录输出logger.info(hello jul);logger.log(Level.INFO, info msg);String name jack;Integer age 18;logger.log(Level.INFO, 用户信息{0},{1}, new Object[]{name, age});}
}2.2 日志级别
JUL一共有7个日志级别用法如下
logger.(Level.INFO,info);Level.SEVERE最高级别的日志主要记录错误信息Level.WARNING级别排行第二记录警告信息Level.INFO级别排行第三最常用的日志级别记录普通消息比如请求信息、连接信息、参数信息等等Level.CONFIG级别排行第四记录配置信息加载配置文件、读取配置参数都可以使用5. CONFIG记录Level.FINE debug 时记录的 日志消息记录运行时的状态、传递的参数等等Level.FINERdebug 时记录的 日志消息记录运行时的状态、传递的参数等等Level.FINESTdebug 时记录的 日志消息记录运行时的状态、传递的参数等等Level.ALL所有记录都开启Level.OFF 关闭日志记录
其中FINE、FINER、FINEST都是记录debug信息的三者取其一即可 虽然我们测试了7个日志级别但是默认只实现info以上的级别 Testpublic void testLogLevel() throws Exception {// 1.获取日志对象Logger logger Logger.getLogger(com.itheima.log.QuickTest);// 2.日志记录输出logger.severe(severe);logger.warning(warning);logger.info(info);logger.config(cofnig);logger.fine(fine);logger.finer(finer);logger.finest(finest);}自定义日志级别配置
Testpublic void testLogConfig() throws Exception {// 1.创建日志记录器对象Logger logger Logger.getLogger(com.itheima.log.JULTest);// 一、自定义日志级别// a.关闭系统默认配置logger.setUseParentHandlers(false);// b.创建handler对象ConsoleHandler consoleHandler new ConsoleHandler();// c.创建formatter对象SimpleFormatter simpleFormatter new SimpleFormatter();// d.进行关联consoleHandler.setFormatter(simpleFormatter);logger.addHandler(consoleHandler);// e.设置日志级别logger.setLevel(Level.ALL);consoleHandler.setLevel(Level.ALL);// 二、输出到日志文件FileHandler fileHandler new FileHandler(d:/logs/jul.log);fileHandler.setFormatter(simpleFormatter);logger.addHandler(fileHandler);// 2.日志记录输出logger.severe(severe);logger.warning(warning);logger.info(info);logger.config(config);logger.fine(fine);logger.finer(finer);logger.finest(finest);}2.3 Logger之间的父子关系
JUL中Logger之间存在父子关系这种父子关系通过树状结构存储JUL在初始化时会创建一个顶层 RootLogger作为所有Logger父Logger存储上作为树状结构的根节点。并父子关系通过路径来关联。
Testpublic void testLogParent() throws Exception {// 日志记录器对象父子关系Logger logger1 Logger.getLogger(com.itheima.log);Logger logger2 Logger.getLogger(com.itheima);System.out.println(logger1.getParent() logger2);// 所有日志记录器对象的顶级父元素 class为java.util.logging.LogManager$RootLoggerSystem.out.println(logger2 parent: logger2.getParent() name logger2.getParent().getName());// 一、自定义日志级别// a.关闭系统默认配置logger2.setUseParentHandlers(false);// b.创建handler对象ConsoleHandler consoleHandler new ConsoleHandler();// c.创建formatter对象SimpleFormatter simpleFormatter new SimpleFormatter();// d.进行关联consoleHandler.setFormatter(simpleFormatter);logger2.addHandler(consoleHandler);// e.设置日志级别logger2.setLevel(Level.ALL);consoleHandler.setLevel(Level.ALL);// 测试日志记录器对象父子关系logger1.severe(severe);logger1.warning(warning);logger1.info(info);logger1.config(config);logger1.fine(fine);logger1.finer(finer);logger1.finest(finest);}2.4 日志的配置文件
默认配置文件路径$JAVAHOME\jre\lib\logging.properties
Test
public void testProperties() throws Exception {
// 读取自定义配置文件
InputStream in
JULTest.class.getClassLoader().getResourceAsStream(logging.properties);
// 获取日志管理器对象
LogManager logManager LogManager.getLogManager();
// 通过日志管理器加载配置文件
logManager.readConfiguration(in);
Logger logger Logger.getLogger(com.itheima.log.JULTest);
logger.severe(severe);
logger.warning(warning);
logger.info(info);
logger.config(config);
logger.fine(fine);
logger.finer(finer);
logger.finest(finest);
}配置文件
#为顶级父元素RootLogger指定默认的处理器:ConsoleHandler,即若是你没有自定义Logger,就用这个Logger
handlersjava.util.logging.ConsoleHandler
#顶级父元素默认的日志级别为INFO,即此Logger的日志级别是INFO
.levelINFO #自定义Logger,即该Logger的name为com.itheima,调用时这样即可 Logger logger Logger.getLogger(com.itheima);
#指定了自定义Logger的handlersConsoleHandler是输出到控制台FileHandler是输出到文件中两个都指定就可以同时输出
com.itheima.handlersjava.util.logging.ConsoleHandler, java.util.logging.FileHandler
#指定了自定义Logger的日志级别
com.itheima.levelINFO
#忽略父日志设置
com.itheima.useParentHandlersfalse#控制台处理器
# 输出日志级别
#指定日志级别 ,尽量和自定义的级别相同否则会有些日志无法打印处理
java.util.logging.ConsoleHandler.levelINFO
#指定日志的格式
java.util.logging.ConsoleHandler.formatterjava.util.logging.SimpleFormatter
#指定日志的编码
java.util.logging.ConsoleHandler.encodingUTF-8
#指定日志消息的格式
java.util.logging.SimpleFormatter.format%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n#文件处理器
# 输出日志级别
java.util.logging.FileHandler.levelINFO
# 输出日志格式
java.util.logging.FileHandler.formatter java.util.logging.SimpleFormatter
# 输出日志文件路径
java.util.logging.FileHandler.pattern /java%u.log
# 输出日志文件限制大小50000字节
java.util.logging.FileHandler.limit 50000
# 输出日志文件限制个数
java.util.logging.FileHandler.count 10
# 输出日志文件 是否是追加
java.util.logging.FileHandler.appendtrue2.5 JUL原理
初始化LogManager LogManager加载logging.properties配置添加Logger到LogManager 从单例LogManager获取Logger设置级别Level并指定日志记录LogRecordFilter提供了日志级别之外更细粒度的控制Handler是用来处理日志输出位置Formatter是用来格式化LogRecord的
3. LOG4J学习
Log4j是Apache下的一款开源的日志框架通过在项目中使用 Log4J我们可以控制日志信息输出到控 制台、文件、甚至是数据库中。我们可以控制每一条日志的输出格式通过定义日志的输出级别可以 更灵活的控制日志的输出过程。方便项目的调试。 log4j 很重要的一个缺陷是不支持占位符但是用户可自己定义实现占位符的功能。 官方网站 http://logging.apache.org/log4j/1.2/
3.1 Log4j入门
建立maven工程添加依赖
dependencygroupIdlog4j/groupIdartifactIdlog4j/artifactIdversion1.2.17/version
/dependency
dependency
groupIdjunit/groupId
artifactIdjunit/artifactId
version4.12/version
/dependencyjava代码
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); // 追踪信息记录程序的所有流程信息
}
}Log4j日志级别
#每个Logger都被了一个日志级别log level用来控制日志信息的输出。日志级别从高到低分
为
fatal 指出每个严重的错误事件将会导致应用程序的退出。
error 指出虽然发生错误事件但仍然不影响系统的继续运行。
warn 表明会出现潜在的错误情形。
info 一般和在粗粒度级别上强调应用程序的运行全程。
debug 一般用于细粒度级别上对调试应用程序非常有帮助。
trace 是程序追踪可以用于输出程序运行中的变量显示执行的流程。
#还有两个特殊的级别
OFF可用来关闭日志记录。
ALL启用所有消息的日志记录。注一般只使用4个级别优先级从高到低为 ERROR WARN INFO DEBUG
3.2 Log4j组件
Log4J 主要由 Loggers (日志记录器)、Appenders输出端和 Layout日志格式化器组成。其中 Loggers 控制日志的输出级别与日志是否输出Appenders 指定日志的输出方式输出到控制台、文件 等Layout 控制日志信息的输出格式。
3.2.1 Loggers
日志记录器负责收集处理日志记录实例的命名就是类“XX”的full quailied name类的全限定名 Logger的名字大小写敏感其命名有继承机制例如name为org.apache.commons的logger会继承 name为org.apache的logger。
Log4J中有一个特殊的logger叫做“root”他是所有logger的根也就意味着其他所有的logger都会直接 或者间接地继承自root。root logger可以用Logger.getRootLogger()方法获取。
但是自log4j 1.2版以来 Logger 类已经取代了 Category 类。对于熟悉早期版本的log4j的人来说 Logger 类可以被视为 Category 类的别名。
3.2.2 Appenders
Appenders ·是用来指定将日志输出到哪个地方可以同时指定日志的输出目的地log4j常用的Appenders有以下几种
输出端类型作用ConsoleAppender将日志输出到控制台FileAppender将日志输出到文件中DailyRollingFileAppender将日志输出到一个日志文件并且每天输出到一个新的文件RollingFileAppender将日志信息输出到一个日志文件并且指定文件的尺寸当文件大小达到指定的尺寸时会自动把文件改名同时产生一个新的文件JDBCAppender把日志信息保存到数据库中
3.2.3 layouts
布局器用于控制日志输出的格式让我么可以自定义日志格式Log4j常用的layouts有以下几种
格式化器作用HTMLLayout格式化日志为html表格形式XMLLayout格式化日志为xml文档形式SimpleLayout默认简单的日志输出格式化打印的日志格式为info - messagePatternLayout最强大的格式化器可以根据自定义格式输出日志如果没有指定转换格式默认的格式只显示消息内容
3.3 Layout的格式
在 log4j.properties 配置文件中我们定义了日志输出级别与输出端在输出端中分别配置日志的输出 格式。
参数说明举例%m输出代码中指定的日志信息logger.info(日志信息)%p输出日志级别INFO、DEBUG、ERROR %-8p 表示占用8个字符若字符不够用空格代替%n换行符必须在结尾加上换行符否则日志将杂乱不堪%r输出从应用启动到输出该log信息耗费的毫秒数log打印时间 - 应用启动时间%c输出打印语句所属的类全名%c com.xd.App %c{1}App%t输出产生该日志所在的线程名名称main 、thread-0、thread-1%d输出服务器当前时间精确到豪秒自定义格式 1、%d 2021-12-16 16:05:07,201 2、 %d{yyyy-MM-dd HH:mm:ss} 2021-12-16 16:05:07%l输出日志发生的位置包含包名、类名、方法名、所在的代码行数com.log.App.haveConfigFile(App.java:25)%L输出代码中的行号12%F显示调用logger的类的文件名App.class%%输出一个百分号 %%
3.4 Appender的输出
控制台文件数据库 log4j的配置文件 log4j.properties放在resources目录下 配置
#指定顶级父元素输出级别与输出端指定日志级别为 INFO使用appender为Console, 这个Console是用户自定义的
log4j.rootLoggerINFO,Console# 控制台输出配置
log4j.appender.Consoleorg.apache.log4j.ConsoleAppender
log4j.appender.Console.layoutorg.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern%d [%t] %-5p [%c] - %m%n# 文件输出配置
log4j.appender.A org.apache.log4j.DailyRollingFileAppender
#指定日志的输出路径
log4j.appender.A.File D:/log.txt
log4j.appender.A.Append true
#使用自定义日志格式化器
log4j.appender.A.layout org.apache.log4j.PatternLayout
#指定日志的输出格式
log4j.appender.A.layout.ConversionPattern %-d{yyyy-MM-dd HH:mm:ss} [%t:%r] -
[%p] %m%n
#指定日志的文件编码
log4j.appender.A.encodingUTF-8#mysql
log4j.appender.logDBorg.apache.log4j.jdbc.JDBCAppender
log4j.appender.logDB.layoutorg.apache.log4j.PatternLayout
log4j.appender.logDB.Drivercom.mysql.jdbc.Driver
log4j.appender.logDB.URLjdbc:mysql://localhost:3306/test
log4j.appender.logDB.Userroot
log4j.appender.logDB.Passwordroot
log4j.appender.logDB.SqlINSERT INTO
log(project_name,create_date,level,category,file_name,thread_name,line,all_categ
ory,message) values(itcast,%d{yyyy-MM-dd
HH:mm:ss},%p,%c,%F,%t,%L,%l,%m)# 自定义Logger会继承父类rootLogger的appenderConsole可以配置取消继承
log4j.logger.com.itheima info,file
log4j.logger.org.apache errorCREATE 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)
);Test
public void testCustomLogger() throws Exception {
// 自定义 com.itheima
Logger logger1 Logger.getLogger(Log4jTest.class);
logger1.fatal(fatal); // 严重错误一般会造成系统崩溃和终止运行
logger1.error(error); // 错误信息但不会影响系统运行
logger1.warn(warn); // 警告信息可能会发生问题
logger1.info(info); // 程序运行信息数据库的连接、网络、IO操作等
logger1.debug(debug); // 调试信息一般在开发阶段使用记录程序的变量、参数等
logger1.trace(trace); // 追踪信息记录程序的所有流程信息
// 自定义 org.apache
Logger logger2 Logger.getLogger(Logger.class);
logger2.fatal(fatal logger2); // 严重错误一般会造成系统崩溃和终止运行
logger2.error(error logger2); // 错误信息但不会影响系统运行
logger2.warn(warn logger2); // 警告信息可能会发生问题
logger2.info(info logger2); // 程序运行信息数据库的连接、网络、IO操作等
logger2.debug(debug logger2); // 调试信息一般在开发阶段使用记录程序的变量、参
数等
logger2.trace(trace logger2); // 追踪信息记录程序的所有流程信息
}4. JCL 学习
全称为Jakarta Commons Logging是Apache提供的一个通用日志API。 它是为 所有的Java日志实现提供一个统一的接口它自身也提供一个日志的实现但是功能非常常弱 SimpleLog。所以一般不会单独使用它。他允许开发人员使用不同的具体日志实现工具: Log4j, Jdk 自带的日志JUL) JCL 有两个基本的抽象类Log(基本记录器)和LogFactory(负责创建Log实例)。
4.1 为什么要用门面技术
面向接口开发不在依赖具体的实现类减少代码的耦合项目通过导入不同的日志实现类可以灵活的切换日志框架统一API方便开发者学习和使用统一配置便于项目日志的管理
4.2 日志实现优先级排列
jcl门面技术在获取log实现时会按照以下顺序依次获取logger的实现我们可以看到它是优先使用log4j的如果找到了log4j的实现就不会在往下找其他实现了
log4j 优先使用log4jjdk14Loggerjdk自带loggerjdk13LumberjackLogger 也是jdk自带loggerSimpleLog jcl自带的日志框架功能比较简单
4.3 JCL入门
1、先添加apache门面的pom依赖
dependencygroupIdcommons-logging/groupIdartifactIdcommons-logging/artifactIdversion1.2/version
/dependency2、java代码
package com.log;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class App {public static void main(String[] args) {Log log LogFactory.getLog(App.class);// jcl优先使用 log4j 日志如果未添加log4j依赖默认会使用java自带的日志框架java.util.logginglog.fatal(fatal);log.error(error);log.warn(warn);log.info(info);log.debug(debug);}
}3、打印结果如下发现默认情况下使用的是jdk自带的日志框架
十二月 17, 2021 11:34:22 上午 com.log.App main
信息: hello world4、接下来我们加上 log4j的依赖
dependencygroupIdlog4j/groupIdartifactIdlog4j/artifactIdversion1.2.17/version
/dependency5、再加上log4j的配置文件 log4j.properties放在resources目录下
# 配置log4j的顶级父元素指定日志级别为 trace使用appender为Console, 这个Console是用户自定义的
log4j.rootLoggertrace,Console
# 指定控制台日志输出的 appender
log4j.appender.Consoleorg.apache.log4j.ConsoleAppender
# 指定消息layout布局器
log4j.appender.Console.layoutorg.apache.log4j.PatternLayout
# 指定消息输出格式
log4j.appender.Console.layout.conversionPattern%t %d [%t] %-5p %l -- %m %n6、其他代码不变再次运行main方法后打印结果如下 会发现自动使用了log4j进行输出日志
main 2021-12-17 11:36:06,642 [main] INFO com.log.App.main(App.java:17) -- hello world 4.4 JCL原理 通过LogFactory动态加载Log实现类 日志门面支持的日志实现数组
private static final String[] classesToDiscover
new String[]{org.apache.commons.logging.impl.Log4JLogger,
org.apache.commons.logging.impl.Jdk14Logger,
org.apache.commons.logging.impl.Jdk13LumberjackLogger,
org.apache.commons.logging.impl.SimpleLog};获取具体的日志实现
for(int i 0; i classesToDiscover.length result null; i) {
result this.createLogFromClass(classesToDiscover[i], logCategory,
true);
}5. 日志门面接口
5.1 什么是日志门面技术
当我们的系统变的更加复杂的时候我们的日志就容易发生混乱。随着系统开发的进行可能会更新不 同的日志框架造成当前系统中存在不同的日志依赖让我们难以统一的管理和控制。就算我们强制要 求所有的模块使用相同的日志框架系统中也难以避免使用其他类似spring,mybatis等其他的第三方框 架它们依赖于我们规定不同的日志框架而且他们自身的日志系统就有着不一致性依然会出来日志 体系的混乱。
所以我们需要借鉴JDBC的思想为日志系统也提供一套门面那么我们就可以面向这些接口规范来开 发避免了直接依赖具体的日志框架。这样我们的系统在日志中就存在了日志的门面和日志的实现。
目前主流的日志门面技术有2种
JCLSLF4J 常见的日志实现 JUL、log4j、logback、log4j2
因为JCL支持的日志技术比较少只支持目前比较主流的日志框架且不支持扩展需要扩展其他的日志实现技术的话需要用户自己修改源代码但是随着技术的发展以后肯定会发展出更多更好的日志框架但是jcl却不支持这些新出的框架因此jcl在在2014年就已经被 apache 给淘汰了目前使用最广泛的是slf4j
5.2 SLF4J的由来
在log4j开发出来出来之后log4j就受到了广大开发者的爱好纷纷开始使用log4j但是后来 log4j的创始人跟apache因为一些矛盾从apache辞职自己去创业了创始人为了给自己的公司打出一点名声所以就基于log4j又开发出了一个新的日志框架 logbacklogback不管是性能还是功能都比log4j强但是却很少人使用 因为jcl门面不支持logback因此jcl在在2014年就已经被 apache 给淘汰了所以这个创世人又设计出了slf4jslf4j支持市面上所有主流的日志框架所以目前为止使用最多的就是slf4j了 后来 apache又基于 logback 的源码 设计出了 log4j2 日志性能上log4j2比logback更胜一筹并且log4j2既是日志框架也是门面技术但是log4j2的门面技术很少人使用大多还是使用slf4j
5.3 为什么要使用SLF4J作为日志门面 使用SLF4J框架可以在部署时迁移到所需的日志记录框架。 SLF4J提供了对所有流行的日志框架的绑定例如log4jJULSimple logging和NOP。因此可以 在部署时切换到任何这些流行的框架。 无论使用哪种绑定SLF4J都支持参数化日志记录消息。由于SLF4J将应用程序和日志记录框架分离 因此可以轻松编写独立于日志记录框架的应用程序。而无需担心用于编写应用程序的日志记录框架。 SLF4J提供了一个简单的Java工具称为迁移器。使用此工具可以迁移现有项目这些项目使用日志 框架(如Jakarta Commons Logging(JCL)或log4j或Java.util.logging(JUL))到SLF4J。
日志门面和日志实现的关系 日志框架出现的历史顺序 log4j --JUL–JCL– slf4j -- logback -- log4j2
6. SLF4J的使用
简单日志门面(Simple Logging Facade For Java) SLF4J主要是为了给Java日志访问提供一套标准、规范 的API框架其主要意义在于提供接口具体的实现可以交由其他日志框架例如log4j和logback等。 当然slf4j自己也提供了功能较为简单的实现但是一般很少用到。对于一般的Java项目而言日志框架 会选择slf4j-api作为门面配上具体的实现框架log4j、logback等中间使用桥接器完成桥接。
SLF4J是目前市面上最流行的日志门面。现在的项目中基本上都是使用SLF4J作为我们的日志系统。 SLF4J日志门面主要提供两大功能
日志框架的绑定日志框架的桥接
6.1 SLF4J入门
1、首先加入slf4j的依赖 !-- 日志门面依赖--dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.27/version/dependency2、java代码
package com.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class App {// 声明日志对象
public final static Logger LOGGER LoggerFactory.getLogger(App .class);
Test
public void testQuick() throws Exception {
//打印日志信息
LOGGER.error(error);
LOGGER.warn(warn);
LOGGER.info(info);
LOGGER.debug(debug);
LOGGER.trace(trace);
// 使用占位符输出日志信息
String name jack;
Integer age 18;
LOGGER.info(用户{},{}, name, age);
// 将系统异常信息写入日志
try {
int i 1 / 0;
} catch (Exception e) {
// e.printStackTrace();
LOGGER.info(出现异常, e);
}
}
}此时还不会打印内容因为目前只有接口还没有具体的实现
6.1.1 slf4j绑定默认日志
slf4j-simple是slf4j内置的简单日志实现框架功能比较简单
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-simple/artifactIdversion1.7.27/version
/dependency运行上述java代码后控制台打印的结果如下
[main] ERROR com.log.App - 12322
[main] WARN com.log.App - warn
[main] INFO com.log.App - info yexindong6.1.1 注意事项
maven依赖中尽量保证只有一个日志实现如果由多个日志实现的话默认使用第一个maven依赖靠前的那个并且在控制台会显示以下警告信息
# 提示有多个日志实现
SLF4J: Class path contains multiple SLF4J bindings.
# 第一个日志实现
SLF4J: Found binding in [jar:file:/D:/repository/org/slf4j/slf4j-simple/1.7.25/ slf4j-simple-1.7.25.jar!/org/slf4j/impl/StaticLoggerBin
# 第二个日志实现
SLF4J: Found binding in [jar:file:/D:/repository/org/slf4j/slf4j-log4j12/1.7.12/slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
# 默认绑定第一个
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]6.2 绑定日志的实现Binding
如前所述SLF4J支持各种日志框架。SLF4J发行版附带了几个称为“SLF4J绑定”的jar文件每个绑定对应 一个受支持的框架。 使用slf4j的日志绑定流程:
添加slf4j-api的依赖使用slf4j的API在项目中进行统一的日志记录绑定具体的日志实现框架 绑定已经实现了slf4j的日志框架,直接添加对应依赖绑定没有实现slf4j的日志框架,先添加日志的适配器,再添加实现类的依赖 slf4j有且仅有一个日志实现框架的绑定如果出现多个默认使用第一个依赖日志实现
6.2.1 slf4j绑定log4j日志框架
其中 slf4j-log4j12 是适配器必须要一个适配器否则log4j不生效
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.27/version
/dependency
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-log4j12/artifactIdversion1.7.27/version
/dependency
dependencygroupIdlog4j/groupIdartifactIdlog4j/artifactIdversion1.2.17/version
/dependency除此之外还需要加上log4j的配置文件log4j.properties
# 配置log4j的顶级父元素指定日志级别为 trace使用appender为yexindong, 这个yexindong 是用户自定义的
log4j.rootLoggertrace,yexindong
# ***********************输出到控制台 start****************
# 指定控制台日志输出的 appender
log4j.appender.yexindongorg.apache.log4j.ConsoleAppender
# 指定消息layout布局器
log4j.appender.yexindong.layoutorg.apache.log4j.PatternLayout
# 指定消息输出格式
log4j.appender.yexindong.layout.conversionPattern%t %d [%t] %-5p %l -- %m %n
# ***********************输出到控制台 end****************6.2.2 slf4j绑定java自带日志框架 jul
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.27/version
/dependency
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-jdk14/artifactIdversion1.7.27/version
/dependency6.2.3 slf4j绑定jcl日志框架
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.27/version
/dependency
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-jcl/artifactIdversion1.7.27/version
/dependency6.2.4 slf4j绑定nop日志框架
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.27/version
/dependency
dependency
groupIdorg.slf4j/groupId
artifactIdslf4j-nop/artifactId
version1.7.27/version
/dependency6.2.5 slf4j绑定logback日志框架绑定已经实现了slf4j的日志框架,直接添加对应依赖
dependencygroupIdch.qos.logback/groupIdartifactIdlogback-classic/artifactIdversion1.2.3/version
/dependency
dependencygroupIdch.qos.logback/groupIdartifactIdlogback-core/artifactIdversion1.2.3/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之外您只需将您选择的一个且只有一个绑定放到相应的类路径位置。不要 在类路径上放置多个绑定。以下是一般概念的图解说明。
6.3 slf4j 日志桥接器Bridging
通常您依赖的某些组件依赖于SLF4J以外的日志记录API。您也可以假设这些组件在不久的将来不会切 换到SLF4J。为了解决这种情况SLF4J附带了几个桥接模块这些模块将对log4jJCL和java.util.logging API的调用重定向就好像它们是对SLF4J API一样。
桥接解决的是项目中日志的遗留问题当系统中存在之前的日志API可以通过桥接转换到slf4j的实现
先去除之前老的日志框架的依赖添加SLF4J提供的桥接组件为项目添加SLF4J的具体实现
例子老项目使用的日志框架是log4j现在想要使用logback 但是一大堆的java文件中都有log4j的导入因为使用了logback就一定要将log4j相关的maven依赖删除依赖删除后这个import导入就一定会报错一个个去改把太麻烦了搞不好改错了更麻烦于是就有了 日志桥接器只需要加上桥接器的maven依赖即可代码一行都不需要改依赖如下
dependencygroupIdorg.slf4j/groupIdartifactIdlog4j-over-slf4j/artifactIdversion1.7.25/version
/dependency加上这个依赖后虽然import上是log4j但是底层调用的其实是logback的日志实现。
迁移的方式
如果我们要使用SLF4J的桥接器替换原有的日志框架那么我们需要做的第一件事情就是删除掉原 有项目中的日志框架的依赖。然后替换成SLF4J提供的桥接器。
!-- log4j--
dependencygroupIdorg.slf4j/groupIdartifactIdlog4j-over-slf4j/artifactIdversion1.7.27/version
/dependency
!-- jul --
dependencygroupIdorg.slf4j/groupIdartifactIdjul-to-slf4j/artifactIdversion1.7.27/version
/dependency
!--jcl --
dependencygroupIdorg.slf4j/groupIdartifactIdjcl-over-slf4j/artifactIdversion1.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等对象将无法产生效果。
6.4 SLF4J原理解析
SLF4J通过LoggerFactory加载日志具体的实现对象。LoggerFactory在初始化的过程中会通过performInitialization()方法绑定具体的日志实现。在绑定具体实现的时候通过类加载器加载org/slf4j/impl/StaticLoggerBinder.class所以只要是一个日志实现框架在org.slf4j.impl包中提供一个自己的StaticLoggerBinder类在 其中提供具体日志实现的LoggerFactory就可以被SLF4J所加载
7. logback
logback是由log4j的创始人设计的另一个开源日志组件性能比log4j更好 logback主要分为三个模块
logback-core其他2个模块的基础模块也是最核心的模块logback-classic它是log4j的一个改良版本同时它完整实现了slf4j APIlogback-access访问模块与servlet容器集成通过http来访问日志的功能
后续的日志代码都是通过SLF4J日志门面搭建日志系统所以在代码是没有区别主要是通过修改配置 文件和pom.xml依赖
logback默认日志级别 logback的默认日志级别是debug
logback配置文件 logback 支持以下几种方式的配置文件如果以下文件都不存在的话则会采用默认的配置文件
logback.groovylogback-test.xmllogback.xml
7.1 logback入门
添加依赖
!-- 使用日志门面管理logback--
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.25/version
/dependency
dependencygroupIdch.qos.logback/groupIdartifactIdlogback-core/artifactIdversion1.2.3/version
/dependency
dependencygroupIdch.qos.logback/groupIdartifactIdlogback-classic/artifactIdversion1.2.3/version
/dependencyjava代码
package com.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//定义日志对象
public final static Logger LOGGER
LoggerFactory.getLogger(LogBackTest.class);
Test
public void testSlf4j(){
//打印日志信息
LOGGER.error(error);
LOGGER.warn(warn);
LOGGER.info(info);
LOGGER.debug(debug);
LOGGER.trace(trace);
}7.2 logback配置
logback会依次读取以下类型配置文件
logback.groovylogback-test.xmllogback.xml 如果均不存在会采用默认配置 logback组件之间的关系 Logger:日志的记录器把它关联到应用的对应的context上后主要用于存放日志对象也 可以定义日志类型、级别。Appender:用于指定日志输出的目的地目的地可以是控制台、文件、数据库等等。Layout:负责把事件转换成字符串格式化的日志信息的输出。在logback中Layout对象被封 装在encoder中。 基本配置信息
?xml version1.0 encodingUTF-8?
configuration
!--
日志输出格式
%-5level
%d{yyyy-MM-dd HH:mm:ss.SSS}日期
%c类的完整名称
%M为method
%L为行号
%thread线程名称
%m或者%msg为信息
%n换行
--
!--格式化输出%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度
%msg日志消息%n是换行符--
property namepattern value%d{yyyy-MM-dd HH:mm:ss.SSS} %c [%thread]
%-5level %msg%n/
!--
Appender: 设置日志信息的去向,常用的有以下几个
ch.qos.logback.core.ConsoleAppender (控制台)
ch.qos.logback.core.rolling.RollingFileAppender (文件大小到达指定尺
寸的时候产生一个新文件)
ch.qos.logback.core.FileAppender (文件)
--
appender nameconsole classch.qos.logback.core.ConsoleAppender
!--输出流对象 默认 System.out 改为 System.err--
targetSystem.err/target
!--日志格式配置--
encoder
classch.qos.logback.classic.encoder.PatternLayoutEncoder
pattern${pattern}/pattern
/encoder
/appender
!--
用来设置某一个包或者具体的某一个类的日志打印级别、以及指定appender。
loger仅有一个name属性一个可选的level和一个可选的addtivity属性
name:
用来指定受此logger约束的某一个包或者具体的某一个类。
level:
用来设置打印级别大小写无关TRACE, DEBUG, INFO, WARN, ERROR, ALL 和
OFF
如果未设置此属性那么当前logger将会继承上级的级别。
additivity:
是否向上级loger传递打印信息。默认是true。
logger可以包含零个或多个appender-ref元素标识这个appender将会添加到这个
logger
--
!--
也是logger元素但是它是根logger。默认debug
level:用来设置打印级别大小写无关TRACE, DEBUG, INFO, WARN, ERROR, ALL
和 OFF
root可以包含零个或多个appender-ref元素标识这个appender将会添加到这个
logger。
--
root levelALL
appender-ref refconsole/
/root
/configurationFileAppender配置
?xml version1.0 encodingUTF-8?
configuration
!-- 自定义属性 可以通过${name}进行引用--
property namepattern value[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c %M
%L [%thread] %m %n/
!--
日志输出格式
%d{pattern}日期
%m或者%msg为信息
%M为method
%L为行号
%c类的完整名称
%thread线程名称
%n换行
%-5level
--
!-- 日志文件存放目录 --
property namelog_dir valued:/logs/property
!--控制台输出appender对象--
appender nameconsole classch.qos.logback.core.ConsoleAppender
!--输出流对象 默认 System.out 改为 System.err--
targetSystem.err/target
!--日志格式配置--
encoder
classch.qos.logback.classic.encoder.PatternLayoutEncoder
pattern${pattern}/pattern
/encoder
/appender
!--日志文件输出appender对象--
appender namefile classch.qos.logback.core.FileAppender
!--日志格式配置--
encoder
classch.qos.logback.classic.encoder.PatternLayoutEncoder
pattern${pattern}/pattern
/encoder
!--日志输出路径--
file${log_dir}/logback.log/file
/appender
!-- 生成html格式appender对象 --
appender namehtmlFile classch.qos.logback.core.FileAppender
!--日志格式配置--
encoder classch.qos.logback.core.encoder.LayoutWrappingEncoder
layout classch.qos.logback.classic.html.HTMLLayout
pattern%level%d{yyyy-MM-dd
HH:mm:ss}%c%M%L%thread%m/pattern
/layout
/encoder
!--日志输出路径--
file${log_dir}/logback.html/file
/appender
!--RootLogger对象--
root levelall
appender-ref refconsole/
appender-ref reffile/
appender-ref refhtmlFile/
/root
/configurationRollingFileAppender配置
?xml version1.0 encodingUTF-8?
configuration!-- 自定义属性 可以通过${name}进行引用--
property namepattern value[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c %M
%L [%thread] %m %n/
!--
日志输出格式
%d{pattern}日期
%m或者%msg为信息
%M为method
%L为行号
%c类的完整名称
%thread线程名称
%n换行
%-5level
--
!-- 日志文件存放目录 --
property namelog_dir valued:/logs/property
!--控制台输出appender对象--
appender nameconsole classch.qos.logback.core.ConsoleAppender
!--输出流对象 默认 System.out 改为 System.err--
targetSystem.err/target
!--日志格式配置--
encoder
classch.qos.logback.classic.encoder.PatternLayoutEncoder
pattern${pattern}/pattern
/encoder
/appender
!-- 日志文件拆分和归档的appender对象--
appender namerollFile
classch.qos.logback.core.rolling.RollingFileAppender
!--日志格式配置--
encoder
classch.qos.logback.classic.encoder.PatternLayoutEncoder
pattern${pattern}/pattern
/encoder
!--日志输出路径--
file${log_dir}/roll_logback.log/file
!--指定日志文件拆分和压缩规则--
rollingPolicy
classch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy
!--通过指定压缩文件名称来确定分割文件方式--
fileNamePattern${log_dir}/rolling.%d{yyyy-MM-
dd}.log%i.gz/fileNamePattern
!--文件拆分大小--
maxFileSize1MB/maxFileSize
/rollingPolicy
/appender
!--RootLogger对象--
root levelall
appender-ref refconsole/
appender-ref refrollFile/
/root
/configurationFilter和异步日志配置
?xml version1.0 encodingUTF-8?
configuration
!-- 自定义属性 可以通过${name}进行引用--
property namepattern value[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c %M
%L [%thread] %m %n/
!--
日志输出格式
%d{pattern}日期
%m或者%msg为信息
%M为method
%L为行号
%c类的完整名称
%thread线程名称
%n换行
%-5level
--
!-- 日志文件存放目录 --
property namelog_dir valued:/logs//property
!--控制台输出appender对象--
appender nameconsole classch.qos.logback.core.ConsoleAppender
!--输出流对象 默认 System.out 改为 System.err--
targetSystem.err/target
!--日志格式配置--
encoder
classch.qos.logback.classic.encoder.PatternLayoutEncoder
pattern${pattern}/pattern
/encoder
/appender
!-- 日志文件拆分和归档的appender对象--
appender namerollFile
classch.qos.logback.core.rolling.RollingFileAppender
!--日志格式配置--
encoder
classch.qos.logback.classic.encoder.PatternLayoutEncoder
pattern${pattern}/pattern
/encoder
!--日志输出路径--
file${log_dir}roll_logback.log/file
!--指定日志文件拆分和压缩规则--
rollingPolicy
classch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy
!--通过指定压缩文件名称来确定分割文件方式--
fileNamePattern${log_dir}rolling.%d{yyyy-MM-
dd}.log%i.gz/fileNamePattern
!--文件拆分大小--
maxFileSize1MB/maxFileSize
/rollingPolicy
!--filter配置--
filter classch.qos.logback.classic.filter.LevelFilter
!--设置拦截日志级别--
levelerror/level
onMatchACCEPT/onMatch
onMismatchDENY/onMismatch
/filter
/appender
!--异步日志--
appender nameasync classch.qos.logback.classic.AsyncAppender
appender-ref refrollFile/
/appender
!--RootLogger对象--
root levelall
appender-ref refconsole/
appender-ref refasync/
/root
!--自定义logger additivity表示是否从 rootLogger继承配置--
logger namecom.itheima leveldebug additivityfalse
appender-ref refconsole/
/logger
/configuration7.3 logback-access的使用
logback-access模块与Servlet容器如Tomcat和Jetty集成以提供HTTP访问日志功能。我们可以使 用logback-access模块来替换tomcat的访问日志。
将logback-access.jar与logback-core.jar复制到$TOMCAT_HOME/lib/目录下修改$TOMCAT_HOME/conf/server.xml中的Host元素中添加
Valve classNamech.qos.logback.access.tomcat.LogbackValve /logback默认会在$TOMCAT_HOME/conf下查找文件 logback-access.xml
?xml version1.0 encodingUTF-8?
configuration
!-- always a good activate OnConsoleStatusListener --
statusListener
classch.qos.logback.core.status.OnConsoleStatusListener/
property nameLOG_DIR value${catalina.base}/logs/
appender nameFILE
classch.qos.logback.core.rolling.RollingFileAppender
file${LOG_DIR}/access.log/file
rollingPolicy
classch.qos.logback.core.rolling.TimeBasedRollingPolicy
fileNamePatternaccess.%d{yyyy-MM-dd}.log.zip/fileNamePattern
/rollingPolicy
encoder
!-- 访问日志的格式 --
patterncombined/pattern
/encoder
/appender
appender-ref refFILE/
/configuration8. log4j2
Apache Log4j 2是对Log4j的升级版参考了logback的一些优秀的设计并且修复了一些问题因此带 来了一些重大的提升主要有
异常处理在logback中Appender中的异常不会被应用感知到但是在log4j2中提供了一些异 常处理机制。性能提升 log4j2相较于log4j 和logback都具有很明显的性能提升后面会有官方测试的数据。自动重载配置参考了logback的设计当然会提供自动刷新参数配置最实用的就是我们在生产 上可以动态的修改日志的级别而不需要重启应用。无垃圾机制log4j2在大部分情况下都可以使用其设计的一套无垃圾机制避免频繁的日志收集 导致的jvm gc。
8.1 Log4j2入门
目前市面上最主流的日志门面就是SLF4J虽然Log4j2也是日志门面因为它的日志实现功能非常强 大性能优越。所以大家一般还是将Log4j2看作是日志的实现Slf4j Log4j2应该是未来的大势所趋。
添加依赖
!-- Log4j2 门面API--
dependency
groupIdorg.apache.logging.log4j/groupId
artifactIdlog4j-api/artifactId
version2.11.1/version
/dependency
!-- Log4j2 日志实现 --
dependency
groupIdorg.apache.logging.log4j/groupId
artifactIdlog4j-core/artifactId
version2.11.1/version
/dependencyJAVA代码
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(info);
LOGGER.debug(debug);
LOGGER.trace(trace);
}
}使用slf4j作为日志的门面,使用log4j2作为日志的实现
!-- Log4j2 门面API--
dependency
groupIdorg.apache.logging.log4j/groupId
artifactIdlog4j-api/artifactId
version2.11.1/version
/dependency
!-- Log4j2 日志实现 --
dependency
groupIdorg.apache.logging.log4j/groupId
artifactIdlog4j-core/artifactId
version2.11.1/version
/dependency
!--使用slf4j作为日志的门面,使用log4j2来记录日志 --
dependency
groupIdorg.slf4j/groupId
artifactIdslf4j-api/artifactId
version1.7.25/version
/dependency
!--为slf4j绑定日志实现 log4j2的适配器 --
dependency
groupIdorg.apache.logging.log4j/groupId
artifactIdlog4j-slf4j-impl/artifactId
version2.10.0/version
/dependency!-- log4j2异步日志依赖 不用异步功能的话这个包可以不要--dependencygroupIdcom.lmax/groupIdartifactIddisruptor/artifactIdversion3.3.4/version/dependency8.2 Log4j2配置
log4j2默认加载classpath下的 log4j2.xml 文件中的配置。
?xml version1.0 encodingUTF-8?
!--日志级别以及优先级排序: OFF FATAL ERROR WARN INFO DEBUG TRACE ALL --
!--Configuration后面的status这个用于设置log4j2自身内部的信息输出可以不设置当设置成trace时你会看到log4j2内部各种详细输出--
!--monitorIntervalLog4j能够自动检测修改配置 文件和重新配置本身设置间隔秒数--
configuration statusWARN monitorInterval30properties!-- 配置全局变量使用时通过${name} 获取--property nameLOG_PATHD:\\log\\/propertyproperty namepattern_format[%d{HH:mm:ss:SSS}] [%-5p] - %l -- %m%n/property/properties!--先定义所有的appender--appenders!--控制台的输出配置--console nameConsole targetSYSTEM_OUT!--输出日志的格式--PatternLayout pattern${pattern_format}//console!--文件会打印出所有信息这个log每次运行程序会自动清空由append属性决定这个也挺有用的适合临时测试用--File namelog fileName${LOG_PATH}/log4j2_all.log appendfalsePatternLayout pattern${pattern_format}//File!-- RandomAccessFile 使用随机读写流输出日志到文件性能较高 --RandomAccessFile namefile fileName${LOG_PATH}/randomAccessFile.logPatternLayout pattern${pattern_format}//RandomAccessFile!-- RollingFile 按照一定的规则进行拆分文件--!-- 这个会打印出所有的info及以下级别的信息每次大小超过size则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩作为存档--RollingFile nameRollingFileInfo fileName${LOG_PATH}/info_low.logfilePattern${LOG_PATH}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log!--控制台只输出level及以上级别的信息onMatch其他的直接拒绝onMismatch--ThresholdFilter levelinfo onMatchACCEPT onMismatchDENY/PatternLayout pattern${pattern_format}/Policies!-- 系统启动或重启时就触发拆分规则生成一个新的日志文件--OnStartupTriggeringPolicy/!-- 按照时间的节点进行拆分 根据filePattern定义的规则拆分--TimeBasedTriggeringPolicy/!-- 按文件大小进行拆分--SizeBasedTriggeringPolicy size100 KB//Policies!-- 在同一目录下日志文件的个数限定为30个超过30个则会覆盖这个配置可以有效防止日志文件过大导致磁盘空间不足 --DefaultRolloverStrategy max30//RollingFile!-- 只打印 info级别的信息--RollingFile nameRollingFileInfo fileName${LOG_PATH}/info.logfilePattern${LOG_PATH}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log!--控制台只输出 info 级别的信息--filters!--onMismatchNEUTRAL 表示该级别及以下的由下一个filter处理如果当前是最后一个则不匹配该级别以下的onMatchDENY 表示不匹配该级别及以上--ThresholdFilter levelwarn onMatchDENY onMismatchNEUTRAL/!--onMatchACCEPT 表示匹配该级别及以上onMismatchDENY 表示不匹配该级别以下的--ThresholdFilter levelinfo onMatchACCEPT onMismatchDENY//filtersPatternLayout pattern${pattern_format}/PoliciesTimeBasedTriggeringPolicy/SizeBasedTriggeringPolicy size100 KB//Policies/RollingFile!-- 只打印warn级别的信息并自动存档--RollingFile nameRollingFileWarn fileName${LOG_PATH}/warn.logfilePattern${LOG_PATH}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log!-- 只打印warn级别的日志--filtersThresholdFilter levelerror onMatchDENY onMismatchNEUTRAL/ThresholdFilter levelwarn onMatchACCEPT onMismatchDENY//filtersPatternLayout pattern${pattern_format}/PoliciesTimeBasedTriggeringPolicy/SizeBasedTriggeringPolicy size100 KB//Policies!-- DefaultRolloverStrategy属性如不设置则默认为最多同一文件夹下7个文件这里设置了20 --DefaultRolloverStrategy max20//RollingFile!-- 打印error级别以上的信息--RollingFile nameRollingFileError fileName${LOG_PATH}/error.logfilePattern${LOG_PATH}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log!-- 只打印error级别的日志--filtersThresholdFilter levelerror onMatchACCEPT onMismatchDENY//filtersPatternLayout pattern${pattern_format}/PoliciesTimeBasedTriggeringPolicy/SizeBasedTriggeringPolicy size100 KB//Policies/RollingFile!-- 每天进行归档自动压缩日志文件 --RollingRandomAccessFile nameapplicationAppender fileName${LOG_PATH}/rollingRandomAccessFile.logfilePattern${LOG_PATH}/$${date:yyyy-MM}/common-%d{yyyy-MM-dd}.log.gzappendtruePatternLayout pattern${pattern_format}/PoliciesTimeBasedTriggeringPolicy//Policies/RollingRandomAccessFile/appenders!--然后定义logger只有定义了logger并引入的appenderappender才会生效--loggers!--过滤掉spring和mybatis的一些无用的DEBUG信息--logger nameorg.springframework levelINFO/loggerlogger nameorg.mybatis levelINFO/loggerroot levelall!-- appender引用--appender-ref refConsole/appender-ref reflog/appender-ref refRollingFileInfo/appender-ref refRollingFileWarn/appender-ref refRollingFileError//root/loggers
/configuration8.3 异步日志
异步日志 log4j2最大的特点就是异步日志其性能的提升主要也是从异步日志中受益我们来看看如何使用log4j2的异步日志。
同步日志 异步日志 Log4j2提供了两种实现日志的方式一个是通过AsyncAppender一个是通过AsyncLogger分别对应 前面我们说的Appender组件和Logger组件。 注意配置异步日志需要添加依赖
!-- log4j2异步日志依赖--
dependencygroupIdcom.lmax/groupIdartifactIddisruptor/artifactIdversion3.3.4/version
/dependencyAsyncAppender方式
?xml version1.0 encodingUTF-8?
Configuration statuswarn
properties
property nameLOG_HOMED:/logs/property
/properties
Appenders
File namefile fileName${LOG_HOME}/myfile.log
PatternLayout
Pattern%d %p %c{1.} [%t] %m%n/Pattern
/PatternLayout
/File
Async nameAsync
AppenderRef reffile/
/Async
/Appenders
Loggers
Root levelerror
AppenderRef refAsync/
/Root
/Loggers
/ConfigurationAsyncLogger方式 AsyncLogger才是log4j2 的重头戏也是官方推荐的异步方式。它可以使得调用Logger.log返回的更快。你可以有两种选择全局异步和混合异步。
全局异步就是所有的日志都异步的记录在配置文件上不用做任何改动只需要在classpath中添加文件log4j2.component.properties文件增加以下内容
Log4jContextSelectororg.apache.logging.log4j.core.async.AsyncLoggerContextSelector混合异步就是你可以在应用中同时使用同步日志和异步日志这使得日志的配置方式更加灵活。
?xml version1.0 encodingUTF-8?
Configuration statusWARN
properties
property nameLOG_HOMED:/logs/property
/properties
Appenders
File namefile fileName${LOG_HOME}/myfile.log
PatternLayout
Pattern%d %p %c{1.} [%t] %m%n/Pattern
/PatternLayout
/File
Async nameAsync
AppenderRef reffile/
/Async
/Appenders
Loggers
AsyncLogger namecom.itheima leveltrace
includeLocationfalse additivityfalse
AppenderRef reffile/
/AsyncLogger
Root levelinfo includeLocationtrue
AppenderRef reffile/
/Root
/Loggers
/Configuration如上配置 com.itheima 日志是异步的root日志是同步的。
使用异步日志需要注意的问题
如果使用异步日志AsyncAppender、AsyncLogger和全局日志不要同时出现。性能会和 AsyncAppender一致降至最低。设置includeLocationfalse 打印位置信息会急剧降低异步日志的性能比同步日志还要 慢。
9. SpringBoot中的日志使用
springboot框架在企业中的使用越来越普遍springboot日志也是开发中常用的日志系统。springboot 默认就是使用SLF4J作为日志门面logback作为日志实现来记录日志。
9.1 SpringBoot中的日志设计
springboot中的日志
dependency
artifactIdspring-boot-starter-logging/artifactId
groupIdorg.springframework.boot/groupId
/dependency依赖关系图 总结
springboot 底层默认使用logback作为日志实现。使用了SLF4J作为日志门面将JUL也转换成slf4j也可以使用log4j2作为日志门面但是最终也是通过slf4j调用logback
9.2 SpringBoot日志使用
在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);
}
}修改默认日志配置
logging.level.com.itheimatrace
# 在控制台输出的日志的格式 同logback
logging.pattern.console%d{yyyy-MM-dd} [%thread] [%-5level] %logger{50} -
%msg%n
# 指定文件中日志输出的格式
logging.fileD:/logs/springboot.log
logging.pattern.file%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n指定配置 给类路径下放上每个日志框架自己的配置文件SpringBoot就不使用默认配置的了
日志框架配置文件Logbacklogback-spring.xml , logback.xmlLog4j2log4j2-spring.xml log4j2.xmlJULlogging.properties
logback.xml直接就被日志框架识别了
使用SpringBoot解析日志配置 logback-spring.xml由SpringBoot解析日志配置
encoder classch.qos.logback.classic.encoder.PatternLayoutEncoder
springProfile namedev
pattern${pattern}/pattern
/springProfile
springProfile namepro
pattern%d{yyyyMMdd:HH:mm:ss.SSS} [%thread] %-5level
%msg%n/pattern
/springProfile
/encoderapplication.properties
spring.profiles.activedev将日志切换为log4j2
dependency
groupIdorg.springframework.boot/groupId
artifactIdspring-boot-starter-web/artifactId
exclusions
!--排除logback--
exclusion
artifactIdspring-boot-starter-logging/artifactId
groupIdorg.springframework.boot/groupId
/exclusion
/exclusions
/dependency
!-- 添加log4j2 --
dependency
groupIdorg.springframework.boot/groupId
artifactIdspring-boot-starter-log4j2/artifactId
/dependency