1. 市面上的日志框架
JUL(java util logging)、logback、log4j、log4j2
JCL(Jakarta Commons Logging)、slf4j(Simple Logging Facade for Java)
日志门面
JCL、slf4j
日志实现
JUL、logback、log4j、log4j2
当初日志的门面根本对立都是应用的 slf4j, 而日志实现的话能够抉择我log4j2 或者logback,这里须要留神一下,slf4j、log4j、logback 这三个是出自同一个人,而 log4j2 则是 Apache 的。
2.SpringBoot 中的默认日志框架
SpringBoot 中默认应用 SLF4J 和 Logback。
3.SpringBoot 中日志框架的应用
在开发的时候,日志记录办法的应用,不应该间接调用日志的实现类,而是调用日志的形象层的办法。
案例:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {public static void main(String[] args) {Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
须要留神的是,slf4j 只是提供接口,每个不同的日志框架的具体实现类须要配置本人的配置文件。
下图是 SLF4J 的官网上的各种实现关系:
引入日志框架如何解决抵触:
当利用的其余 jar 中有其余的日志实现,就会导致抵触,就须要用两头的 jar 进行替换,才能够解决,下图就是 slf4j 官网的抵触的解决图。
如何让利用的中 jar 对立应用 slf4j(即如上图展现):
- 将零碎中其余日志框架先排除进来;
- 用两头包来替换原有的日志框架;
- 咱们导入 slf4j 其余的实现(咱们本人想用的实现)
3.1 SpringBoot 中的日志关系
SpringBoot 应用它来做日志性能:
当咱们引入 springboot 的 web 模块时,就引入这个依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐logging</artifactId>
</dependency>
底层依赖关系:
总结:
1)、SpringBoot 底层也是应用 slf4j+logback 的形式进行日志记录
2)、SpringBoot 也把其余的日志都替换成了 slf4j;
3)、两头替换包的引入
两头替换包的简略案例:
@SuppressWarnings("rawtypes")
public abstract class LogFactory {
static String UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J =
"http://www.slf4j.org/codes.html#unsupported_operation_in_jcl_over_slf4j";
static LogFactory logFactory = new SLF4JLogFactory();
他在代码中做了替换,包名还是和你原来应用的包名一样,尽管你应用的还是原来的,然而真正的实现类曾经被替换了。
4)、如果咱们要引入其余框架?肯定要把这个框架的默认日志依赖移除掉
eg:
Spring 框架用的是 commons-logging;
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring‐core</artifactId>
<exclusions>
<exclusion>
<groupId>commons‐logging</groupId>
<artifactId>commons‐logging</artifactId>
</exclusion>
</exclusions>
</dependency>
SpringBoot 能主动适配所有的日志,而且底层应用 slf4j+logback 的形式记录日志,引入其余框架的时候,只须要
把这个框架依赖的日志框架排除掉即可;
3.2 SpringBoot 中日志的配置与应用
1. 默认配置
SpringBoot 默认帮咱们配置好了日志;咱们间接启动我的项目就能够看到控制台有日志输入。
// 记录器
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void contextLoads() {
// 日志的级别;// 由低到高 trace<debug<info<warn<error
// 能够调整输入的日志级别;日志就只会在这个级别以当前的高级别失效
logger.trace("这是 trace 日志...");
logger.debug("这是 debug 日志...");
//SpringBoot 默认给咱们应用的是 info 级别的,没有指定级别的就用 SpringBoot 默认规定的级别;root 级别
logger.info("这是 info 日志...");
logger.warn("这是 warn 日志...");
logger.error("这是 error 日志...");
}
日志输入格局:
%d 示意日期工夫,%thread 示意线程名,%‐5level:级别从左显示 5 个字符宽度
%logger{50} 示意 logger 名字最长 50 个字符,否则依照句点宰割。%msg:日志音讯,%n 是换行符
‐‐>
%d{yyyy‐MM‐dd HH:mm:ss.SSS} [%thread] %‐5level %logger{50} ‐ %msg%n
2. 批改日志的默认配置
在 springboot 的配置文件中批改默认配置
# 指定某个包下的类的日志输入级别
logging.level.com.njit=trace
# 设置 springboot 默认的日志级别,springboot 默认的日志级别就是 root,这里指定 root 的具体级别
# logging.level.root=warn
# 不指定门路在以后我的项目下生成 springboot.log 日志
# 能够指定残缺的门路;#logging.file=D:/springboot.log
# 在以后磁盘的根门路下创立 spring 文件夹和外面的 log 文件夹;应用 spring.log 作为默认文件
logging.path=/spring/log
# 在控制台输入的日志的格局
logging.pattern.console=%d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n
# 指定文件中日志输入的格局
logging.pattern.file=%d{yyyy‐MM‐dd} === [%thread] === %‐5level === %logger{50} ==== %msg%n
注:如果 logging.path 和 logging.file 同时存在,则以 logging.file 为准
通过本人的配置文件笼罩默认的配置
springboot 中的默认配置文件在你引入的 springboot 的依赖下的 logging 目录下,有 log4j2 和 logback 的默认配置:
如果你在给类门路下放上每个日志框架本人的配置文件即可;SpringBoot 就不应用他默认配置的了
logback.xml:间接就被日志框架辨认了;
logback-spring.xml:日志框架就不间接加载日志的配置项,由 SpringBoot 解析日志配置,能够应用 SpringBoot 的高级 Profile 性能
<springProfile name="staging">
<!‐‐ configuration to be enabled when the "staging" profile is active ‐‐>
能够指定某段配置只在某个环境下失效
</springProfile>
比方,在 dev 环境输入的格局和非 dev 环境的格局不同,能够指定不同的:
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!‐‐
日志输入格局:%d 示意日期工夫,%thread 示意线程名,%‐5level:级别从左显示 5 个字符宽度
%logger{50} 示意 logger 名字最长 50 个字符,否则依照句点宰割。%msg:日志音讯,%n 是换行符
‐‐>
<layout class="ch.qos.logback.classic.PatternLayout">
<springProfile name="dev">
<pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ‐‐‐‐> [%thread] ‐‐‐> %‐5level
%logger{50} ‐ %msg%n</pattern>
</springProfile>
<springProfile name="!dev">
<pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ==== [%thread] ==== %‐5level
%logger{50} ‐ %msg%n</pattern>
</springProfile>
</layout>
</appender>
如果应用 logback.xml 作为日志配置文件,还要应用 profile 性能,会有以下谬误no applicable action for [springProfile]
3.logback 的配置文件参考
logback 会顺次读取以下类型配置文件:
- logback.groovy
- logback-test.xml
- logback.xml 如果均不存在会采纳默认配置
logback 组件之间的关系
- Logger: 日志的记录器,把它关联到利用的对应的 context 上后,次要用于寄存日志对象,也
能够定义日志类型、级别。
- Appender: 用于指定日志输入的目的地,目的地能够是控制台、文件、数据库等等。
- Layout: 负责把事件转换成字符串,格式化的日志信息的输入。在 logback 中 Layout 对象被封
装在 encoder 中。
根本配置信息
<?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 个字符宽度
%msg:日志音讯,%n 是换行符 -->
<property name="pattern" 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 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>。<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 level="ALL">
<appender-ref ref="console"/>
</root>
</configuration>
FileAppender 配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 自定义属性 能够通过 ${name}进行援用 -->
<property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss} %c %M %L [%thread] %m %n"/>
<!--
日志输入格局:%d{pattern}日期
%m 或者 %msg 为信息
%M 为 method
%L 为行号
4. RollingFileAppender 配置
%c 类的残缺名称
%thread 线程名称
%n 换行
%-5level
-->
<!-- 日志文件寄存目录 -->
<property name="log_dir" value="d:/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="file" class="ch.qos.logback.core.FileAppender">
<!-- 日志格局配置 -->
<encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
<!-- 日志输入门路 -->
<file>${log_dir}/logback.log</file>
</appender>
<!-- 生成 html 格局 appender 对象 -->
<appender name="htmlFile" class="ch.qos.logback.core.FileAppender">
<!-- 日志格局配置 -->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.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 level="all">
<appender-ref ref="console"/>
<appender-ref ref="file"/>
<appender-ref ref="htmlFile"/>
</root>
</configuration>
RollingFileAppender 配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 自定义属性 能够通过 ${name}进行援用 -->
<property name="pattern" 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 name="log_dir" value="d:/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="rollFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志格局配置 -->
<encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
<!-- 日志输入门路 -->
<file>${log_dir}/roll_logback.log</file>
<!-- 指定日志文件拆分和压缩规定 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 通过指定压缩文件名称,来确定宰割文件形式 -->
<fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-
dd}.log%i.gz</fileNamePattern>
<!-- 文件拆分大小 -->
<maxFileSize>1MB</maxFileSize>
</rollingPolicy>
</appender>
<!--RootLogger 对象 -->
<root level="all">
<appender-ref ref="console"/>
<appender-ref ref="rollFile"/>
</root>
</configuration>
Filter 和异步日志配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 自定义属性 能够通过 ${name}进行援用 -->
<property name="pattern" 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 name="log_dir" value="d:/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="rollFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志格局配置 -->
<encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
<!-- 日志输入门路 -->
<file>${log_dir}roll_logback.log</file>
<!-- 指定日志文件拆分和压缩规定 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 通过指定压缩文件名称,来确定宰割文件形式 -->
<fileNamePattern>${log_dir}rolling.%d{yyyy-MM-
dd}.log%i.gz</fileNamePattern>
<!-- 文件拆分大小 -->
<maxFileSize>1MB</maxFileSize>
</rollingPolicy>
<!--filter 配置 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 设置拦挡日志级别 -->
<level>error</level>
<onMatch>ACCEPT</onMatch>
6. 官网提供的 log4j.properties 转换成 logback.xml
https://logback.qos.ch/translator/
3.3 logback-access 的应用
logback-access 模块与 Servlet 容器(如 Tomcat 和 Jetty)集成,以提供 HTTP 拜访日志性能。咱们能够使
用 logback-access 模块来替换 tomcat 的拜访日志。1. 将 logback-access.jar 与 logback-core.jar 复制到 $TOMCAT_HOME/lib/ 目录下
2. 批改 $TOMCAT_HOME/conf/server.xml 中的 Host 元素中增加:3. logback 默认会在 $TOMCAT_HOME/conf 下查找文件 logback-access.xml
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步日志 -->
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="rollFile"/>
</appender>
<!--RootLogger 对象 -->
<root level="all">
<appender-ref ref="console"/>
<appender-ref ref="async"/>
</root>
<!-- 自定义 logger additivity 示意是否从 rootLogger 继承配置 -->
<logger name="com.itheima" level="debug" additivity="false">
<appender-ref ref="console"/>
</logger>
</configuration>
4.log4j2 的配置文件参考
Apache Log4j 2 是对 Log4j 的升级版,参考了 logback 的一些优良的设计,并且修复了一些问题,因而带来了一些重大的晋升,次要有:
- 异样解决,在 logback 中,Appender 中的异样不会被利用感知到,然而在 log4j2 中,提供了一些异样解决机制。
- 性能晋升,log4j2 相较于 log4j 和 logback 都具备很显著的性能晋升,前面会有官网测试的数据。主动重载配置,参考了 logback 的设计,当然会提供主动刷新参数配置,最实用的就是咱们在生产上能够动静的批改日志的级别而不须要重启利用。
- 无垃圾机制,log4j2 在大部分状况下,都能够应用其设计的一套无垃圾机制,防止频繁的日志收集
导致的 jvm gc.
log4j2 默认加载 classpath 下的 log4j2.xml 文件中的配置
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" monitorInterval="5">
<properties>
<property name="LOG_HOME">D:/logs</property>
</properties>
4.3 Log4j2 异步日志
异步日志
log4j2 最大的特点就是异步日志,其性能的晋升次要也是从异步日志中受害,咱们来看看如何应用
log4j2 的异步日志。同步日志
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n"/>
</Console>
<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>
<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>
<RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log"
filePattern="D:/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/>
<SizeBasedTriggeringPolicy size="10 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
5.log4j2 的异步日志
log4j2 最大的特点就是异步日志,其性能的晋升次要也是从异步日志中受害,咱们来看看如何应用 log4j2 的异步日志。
- 同步日志示意图
- 异步日志示意图
Log4j2 提供了两种实现日志的形式,一个是通过 AsyncAppender,一个是通过 AsyncLogger,别离对应后面咱们说的 Appender 组件和 Logger 组件。
留神:配置异步日志须要增加依赖:
<!-- 异步日志依赖 -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.4</version>
</dependency>
5.1. AsyncAppender 形式
<?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>
5.2. AsyncLogger 形式
AsyncLogger 才是 log4j2 的重头戏,也是官网举荐的异步形式。它能够使得调用 Logger.log 返回的更快。你能够有两种抉择:全局异步和混合异步。
- 全局异步就是,所有的日志都异步的记录,在配置文件上不必做任何改变,只须要增加一个 log4j2.component.properties 配置;
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>
<AsyncLogger name="com.njit" level="trace"
includeLocation="false" additivity="false">
<AppenderRef ref="file"/>
</AsyncLogger>
<Root level="info" includeLocation="true">
<AppenderRef ref="file"/>
</Root>
</Loggers>
</Configuration>
如上配置:com.njit 日志是异步的,root 日志是同步的。
应用异步日志须要留神的问题:
- 如果应用异步日志,AsyncAppender、AsyncLogger 和全局日志,不要同时呈现。性能会和 AsyncAppender 统一,降至最低。
- 设置 includeLocation=false,打印地位信息会急剧升高异步日志的性能,比同步日志还要慢。