主要内容
1.日志框架
2.日志配置
1、日志框架
1.1 背景
小张开发一个大型系统;
1、System.out.println("");将关键数据打印在控制台;去掉?写在一个文件?
2、框架来记录系统的一些运行时信息;日志框架 ; zhanglogging.jar;
3、高大上的几个功能?异步模式?自动归档?xxxx? zhanglogging-good.jar?
4、将以前框架卸下来?换上新的框架,重新修改之前相关的API;zhanglogging-prefect.jar;
5、JDBC---数据库驱动;
写了一个统一的接口层;日志门面(日志的一个抽象层);logging-abstract.jar;
给项目中导入具体的日志实现就行了;我们之前的日志框架都是实现的抽象层;
1.2 市面上的日志框架
JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j....
| 日志门面 (日志的抽象层) | 日志实现 |
|---|---|
| Log4j JUL(java.util.logging) Log4j2 Logback |
左边选一个门面(抽象层)、右边来选一个实现;
日志门面: SLF4J;
日志实现:Logback;
SpringBoot:底层是Spring框架,Spring框架默认是用JCL;
==SpringBoot选用 SLF4j和logback;==
2、SLF4J使用
2.1 如何在系统中使用SLF4J
以后开发的时候,日志记录方法的调用,不应该直接调用日志的实现类,而是调用日志抽
象层里面的方法。它会自动调用实现类中的方法。
默认用的是Logback的实现jar,应该给系统中导入slf4j的jar和logback的实现jar。
当然也可以用其他的实现jar,毕竟slf4j是一个抽象接口层
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");
}
}
2.2 图示:
第一列:只导了slf4j抽象层的jar,没有导入具体日志实现。
结果只能在打出一些空的信息。 /dev/null
第二列:导入slf4j的jar和logback的jar
有抽象接口框架,也有具体的日志实现。
这就是使用slf4j的方式
第三列:日志实现选择log4j
因为log4j出现较早,没有考虑到日志抽象层的情况。
所以要想用lof4j日志实现那么中间要加一层适配层。
每一个日志的实现框架都有自己的配置文件。
使用slf4j后,配置文件还是用日志实现框架的本身的配置文件。
2.3 遗留问题
假设我们开发了一个a系统,日志框架采用(slf4j+logback)。而且a系统用到了
Spring,Hibernate,Mybatis....等等框架。这些框架很可能底层也用到了框架,而且
各不相同。
比如,Spring底层用的是(commons-logging)做的日志,Hibernate用的是(jboss-logging)
那么就出现了问题:
同一个系统出现了各种各样的日志框架。
统一日志记录:
即使是别的框架也统一使用slf4j进行输出。
2.4 解决遗留问题:
项目中用到的所有日志框架统一使用slf4j+logback进行日志记录
具体做法:统一使用slf4j+logback
1. 我们项目选用slf4j+logback
应用程序面向slf4j(接口层)编程,真正的实现我们用的是logback。
2. 发现该程序编写时依赖其他的框架,而其他的框架底层用不同的日志框架记录信息。
比如Spring中的commons-logging
我们想要这些日志框架都能使用到slf4j。
3. 我们可以将这些日志框架的jar(依赖)删掉。
但是删掉后,该框架显然不能在使用了。比如Spring底层用commons-logging来记录
信息。
那么我们可以考虑用一个类似的jar来代替原来jar。
4. 替换jar
比如我们用jcl-over-slf4j.jar来代替commons-logging.jar
这个代替的jar的功能和commons-logging.jar一样,该有的类,API一样。
即Spring框架要用的commons-logging.jar里面的类,方法在jcl-over-slf4j.jar
都有。那么Spring框架就不会报错了。
但是新的包真正的实现是slf4j,slf4j的实现就又调到了logback。
相当于中间又有了一个适配层,包装层。
5. 如果项目想用slfj+log4j来做日志框架
统一日志框架也用上面的方法。
3. SpringBoot日志关系
我们新建一个项目,来看一下SpringBoot中的依赖。
1. spring-boot-starter是SpringBoot项目最基本的依赖,每个场景都会依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.1.RELEASE</version>
<scope>compile</scope>
</dependency>
spring-boot-starter又会依赖:
spring-boot-autoconfigure
spring-boot-starter-logging
2. 我们来看一下日志的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.3.1.RELEASE</version>
<scope>compile</scope>
</dependency>
这个日志依赖底层又依赖了许多jar,来将用到的日志都统一成slf4j。
这就是SpringBoot底层日志依赖关系。
3. 总结:
1.SpringBoot底层也是使用slf4j+logback的方式进行日志记录。
2.SpringBoot也把其他的日志都替换成了slf4j
3.中间替换包实现的是slf4j
4.如果我们要引入其他框架,一定要把框架的默认依赖移除掉。
4. 这也是SpringBoot的做法。
所以SpringBoot能自动适配所有的日志,而且底层使用的是slf4j+back的方式记录,
引入其他框架的时候,只需要把它的日志框架的依赖排除掉,不用再做其他的配置。
4. SpringBoot日志的使用
4.1 SpringBoot日志的使用
SpringBoot默认帮我们配置好了日志,使用方式如下。
@SpringBootTest
class Day0626Springboot04LoggingApplicationTests {
//获得一个日志记录器
Logger logger = LoggerFactory.getLogger(getClass());
@Test
void contextLoads() {
// System.out.println();
//日志的级别:由低到高
//可以调整输出的日志级别:只打印某个级别和大于其级别的内容
logger.trace(()->"这是trace日志...");
logger.debug(()->"这是debug日志...");
logger.info(()->"这是Info日志...");
logger.warn(()->"这是warn日志...");
logger.error(()->"这是error日志...");
}
}
运行test方法测试一下:
发现只打印了info及大于其级别的内容。
4.2 SpringBoot日志的调整配置
1.在主配置文件中配置日志级别:
配置com.atguigu包下的类:所有的日志级别是trace
没有指定级别,就要SpringBoot默认规定的级别:root级别
2. logging.file.name/logging.file.path
这两个属性有冲突,一般只用一个。常用logging.file.path。
这两个属性不配置的话,默认将日志信息在控制台输出。
1.logging.file.name
#当前项目下生成springboot.log日志:也会打印到控制台
logging.file.name=springboot.log
#在指定路径下生成springboot.log日志
logging.file.name=F:/springboot.log
2. logging.file.path
# 在当前项目所在磁盘的根路径下创建: /springboot/log/springboot.log
logging.file.path=/spring/log
3. 日志输出格式。
默认是:时间+日志级别+线程id+全类名+消息
我们可以自己规定格式:
默认的格式写法:
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
日志输出格式分析:
%d表示日期时间
%thread表示线程名
%-5level:级别从左显示五个字符宽度
%logger{50} :表示logger名字最长50个字符,否则按照据点分割。
%msg:日志消息
%n:换行符。
4. SpringBoot给我们默认配置好了日志。
如果还想要进行配置,在类路径下放上每个日志框架对应的配置文件即可;SpringBoot就不使用他默认配置的日志配置了。
logback.xml 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<!-- 定义日志的根目录 -->
<property name="LOG_HOME" value="/app/log" />
<!-- 定义日志文件名称 -->
<property name="appName" value="atguigu-springboot"></property>
<!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
<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">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender>
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 指定日志文件的名称 -->
<file>${LOG_HOME}/${appName}.log</file>
<!--
当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--
滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
%i:当文件大小超过maxFileSize时,按照i进行文件滚动
-->
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!--
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
那些为了归档而创建的目录也会被删除。
-->
<MaxHistory>365</MaxHistory>
<!--
当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 日志输出格式: -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
</layout>
</appender>
<!--
logger主要用于存放日志对象,也可以定义日志类型、级别
name:表示匹配的logger类型前缀,也就是包的前半部分
level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,
false:表示只用当前logger的appender-ref,true:
表示当前logger的appender-ref和rootLogger的appender-ref都有效
-->
<!-- hibernate logger -->
<logger name="com.atguigu" level="debug" />
<!-- Spring framework logger -->
<logger name="org.springframework" level="debug" additivity="false"></logger>
<!--
root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,
要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。
-->
<root level="info">
<appender-ref ref="stdout" />
<appender-ref ref="appLogAppender" />
</root>
</configuration>
5. 日志框架和日志配置文件的对应关系:
logback : logback.xml
log4j2 : log4j2.xml
JDK(java util logging) : logging.properties
高级特性:<springProfile>只在某个环境中激活该配置文件。
logback:xml:
直接就被日志框架识别了。
logback-spring.xml:
日志框架就不直接加载了,由SpringBoot加载。那么就能用到SpringBoot一个
非常好的功能:<springProfile>只在某个环境中激活该配置文件。
建议使用logback-spring.xml来做日志配置文件。
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<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} 6666 [%thread] 6666 %-5level %logger{50} - %msg%n</pattern>
</springProfile>
</layout>
</appender>
注意:使用自己写的日志配置文件时,要注解掉主配置文件中关于日志的配置,去掉有冲突的配置。
5 切换日志框架
例如:
我们现在用的是slf4j+logback的日志框架,怎么切换到是slf4j+log4j?
此处只做举例:因为这是没意义的本来log4j就是因为作者觉得不好,才写了logback的。
1. 我们在pom.xml打开依赖结构
2. 再排除掉默认的logback的依赖
3. 导入适配层的包
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
4. 测试一下
5. 加一个lof4j的配置文件
可以按照slf4j的日志适配图进行相关的切换;
5.2 转成Log4j2
转成Log4j2:
将依赖中的starter-loggingExclude掉:
spring-boot-starter-logging
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
导入:oot-starter-log4j2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>