内容简介:Spring Boot: 底层是Spring框架,Spring框架默认是JCL;而Spring Boot选用 SLF4j和Logback
版本:
-
Spring Boot 2.1.5.RELEASE
-
maven 3.2.5
-
jdk1.8
1.我选用的日志框架:
- 日志门面(抽象层): SLF4J
- 日志实现: Logback
Spring Boot: 底层是Spring框架,Spring框架默认是JCL;
而Spring Boot选用 SLF4j和Logback
2. SLF4j使用
1) 如何在系统中使用SLF4j
开发的时候,日志记录方法的调用,不用改直接调用日志的实现类,而是调用日志抽象层里的方法;
- 导入slf4j的jar和 logback的实现jar
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与其他日志框架结合示意图:
2) 遗留问题
虽然我使用的是(slf4j & logback),但是其他的比如Spring框架用的 commons-logging 日志框架, Hibernate用的是 jboss-logging 日志框架,等等,太乱了了,所以我们要 统一日志记录,即使别的框架也要和我一起统一使用slf4j进行输出 ;
官方给出的示意图:
逻辑:
- 1.将系统其他的日志框架排除;
- 2.用中间包来替换原有的日志框架(红色框起来的就是中间包);
- 3.导入slf4j其他的实现
3. Spring Boot日志关系
其实是这个依赖的这个包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.1.5.RELEASE</version>
<scope>compile</scope>
</dependency>
复制代码
在 pom文件下 鼠标右键点击:
SpringBoot所有依赖关系图,我们只看logging相关的:
我用的是2.1.5版本的Spring Boot, 笔者在学习过程中发现我看的老师视频里跟我的版本不一样,
这是那位老师的版本:
很明显跟我不一样,不过Spring肯定对自己的底层进行了升级;
确切的说不是升级,而是剔除掉了jcl框架的转换,因为jcl框架最后更新日期是2014年,明显已经过时
但是基本推理的出来,slf4j的官网图确实是对SpringBoot1.x版本的示意,但是对我的2.x版本不符, 不过根据我的包名来看,他们的功能是差不多的,都是转成slf4j;
小总结:
- 1.SpringBoot底层也是 slf4j+logback的方式j进行日志记录;
- 2.SpringBoot也把其他日志都替换成了slf4j;
- 3.中间替换包;
中间替换包图示:
4) 如果我们要引入其他的框架,一定要把这个框架默认日志依赖移除掉!
Spring框架默认的日志框架是: commons-logging;
但是Spring Boot引入spring核心jar包的时候去除了 日志jar包;
Spring Boot能自动适配所有的日志,而且底层使用 slf4j+logback的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志排除掉
4. 日志使用
测试类:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootLoggingApplicationTests {
// 日志记录器记录器
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void contextLoads() {
// 日志的级别
// 由低到高 trace < debug < info < warn < error
logger.trace("这是trace日志..");
logger.debug("这是debug调试日志..");
logger.info("这是info日志..");
logger.warn("这是warn日志...");
logger.error("这是error错误日志");
}
}
复制代码
运行输出结果:
2019-07-02 19:22:35.980 INFO 8404 --- [ main] c.c.s.SpringBootLoggingApplicationTests : 这是info日志.. 2019-07-02 19:22:35.981 WARN 8404 --- [ main] c.c.s.SpringBootLoggingApplicationTests : 这是warn日志... 2019-07-02 19:22:35.981 ERROR 8404 --- [ main] c.c.s.SpringBootLoggingApplicationTests : 这是error错误日志 复制代码
也就是说 SpringBoot默认的日志级别是 info ,所以只输出了info 和 比info级别大的日志;
打开我的yml配置文件:
logging:
level:
com.carson: trace
复制代码
意思是把我 com.carson下的所有包都设置为 trace 日志级别
输出结果:
2019-07-02 19:29:17.406 TRACE 7076 --- [ main] c.c.s.SpringBootLoggingApplicationTests : 这是trace日志.. 2019-07-02 19:29:17.407 DEBUG 7076 --- [ main] c.c.s.SpringBootLoggingApplicationTests : 这是debug调试日志.. 2019-07-02 19:29:17.407 INFO 7076 --- [ main] c.c.s.SpringBootLoggingApplicationTests : 这是info日志.. 2019-07-02 19:29:17.408 WARN 7076 --- [ main] c.c.s.SpringBootLoggingApplicationTests : 这是warn日志... 2019-07-02 19:29:17.408 ERROR 7076 --- [ main] c.c.s.SpringBootLoggingApplicationTests : 这是error错误日志 复制代码
4.1 配置文件详解:
logging.level.com.carson= trace
# path: 只创建任意一个文件夹, SpringBoot会默认生成一个 spring.log 作为日志文件
logging.path= F:/spring/log
# file: 指定一个路径和文件把 日志输出到 指定文件里
logging.file= F:/springboot.log
# pattern.console: 控制台输出的日志格式
logging.pattern.console= %d{yyyy‐MM‐dd} === [%thread] === %‐5level === %logger{50} ==== %msg%n
# pattern.file : 指定文件中日志的输出格式
logging.pattern.file= %d{yyyy‐MM‐dd} === [%thread] === %‐5level === %logger{50} ==== %msg%n
复制代码
4.2 指定配置
| 日志框架 | 文件命名 |
|---|---|
| Logback | logback-spring.xml , logback-spring.groovy , logback.xml , or logback.groovy |
| Log4j2 | log4j2-spring.xml or log4j2.xml |
| JDK (Java Util Logging) | logging.properties |
以上来自SpringBoot的官方文档, 上面是他要求的命名,SpringBoot会读取的
- logback-spring.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">
<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>
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<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>
复制代码
把上面配置复制一份,放到项目的 resources 里面,或者自定义配置,命名规范的区别:
-
logback.xml: 直接被日志框架识别了
-
但是如果你以 logback-spring.xml 命名(推荐): 日志框架不直接加载日志的配置项了,由SpringBoot解析日志你就可以使用SpringBoot的一个高级功能
<springProfile name="prod"> <!-- 是不是 prod 环境 --> </springProfile> <springProfile name="dev | prod"> <!-- dev 和 prod 都会执行 --> </springProfile> <springProfile name="!dev"> <!-- 如果不是 dev环境 --> </springProfile> 复制代码
也就是刚才的配置文件里的:
<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>
复制代码
你可以在你的 yml或者properties里配置一条:
spring.profiles.active= prod 复制代码
来设置运行环境
4.3 使用 log4j
其实SpringBoot官方为我们做了一些帮助:
| Name | Description | Pom |
|---|---|---|
spring-boot-starter-jetty |
Starter for using Jetty as the embedded servlet container. An alternative to spring-boot-starter-tomcat |
Pom |
spring-boot-starter-log4j2 |
Starter for using Log4j2 for logging. An alternative to spring-boot-starter-logging |
Pom |
spring-boot-starter-logging |
Starter for logging using Logback. Default logging starter | Pom |
spring-boot-starter-reactor-netty |
Starter for using Reactor Netty as the embedded reactive HTTP server. | Pom |
spring-boot-starter-tomcat |
Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web |
Pom |
spring-boot-starter-undertow |
Starter for using Undertow as the embedded servlet container. An alternative to spring-boot-starter-tomcat |
Pom |
想使用哪个日志框架就直接导入哪个包就好了, 比如我想使用 log4j2 我先把默认的 spring-boot-starter-logging 排除掉 , 排除方法如下:
- 然后再pom文件里:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
复制代码
导入log4j2的包;
- 然后在 resources 里 创建一个 log4j的配置文件,文件命名就以刚才说的:
内容:
### set log levels ###
log4j.rootLogger = debug , stdout , D , E
### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} ===== %5p %c{ 1 }:%L - %m%n
#### 输出到日志文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/log.log
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志
#log4j.appender.D.layout = org.apache.log4j.PatternLayout
#log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
#
#### 保存异常信息到单独文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/error.log ## 异常日志文件名
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = ERROR ## 只输出ERROR级别以上的日志!!!
#log4j.appender.D.layout = org.apache.log4j.PatternLayout
#log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
复制代码
也就是说,如果像引入其他日志框架,只要把以前的框架排除,然后再引入新框架就ok了
个人博客 :aaatao66.github.io/
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Is Parallel Programming Hard, And, If So, What Can You Do About
Paul E. McKenney
The purpose of this book is to help you understand how to program shared-memory parallel machines without risking your sanity.1 By describing the algorithms and designs that have worked well in the pa......一起来看看 《Is Parallel Programming Hard, And, If So, What Can You Do About 》 这本书的介绍吧!