牢记:慎用System.out.println();尽量使用log4j2或者logback等日志来记录信息。
理由如下:
- System.out.println()是一个同步方法,当我们在性能要求比较高、高并发的时候(毫秒级别时),使用System.out.println()就会导致进程在执行它时不能异步进行,导致浪费大量时间,从而对性能产生影响
public void println(String x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
//在使用System.out.println()输出时,会使用同步锁将其锁起来,所有其是一个同步方法
synchronized (this) {
print(x);
newLine();
}
}
}
所以务必养成一个好习惯,在日常开发或者调试的过程中,使用日志这些异步方法来输出及进行日志的统一收集,在一个项目上线前,也要进行全局的搜索,防止误用了System.out.println()
关于为啥要使用日志就说这么多,接下来我们来看看SpringBoot3中的日志使用
日志
当项目一启动时,日志就开始相应的创建。默认使用logback + slf4j组合来作为默认的底层日志
1.1、日志默认格式
2023-03-31T13:56:17.511+08:00 INFO 4944 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-03-31T13:56:17.511+08:00 INFO 4944 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.7]
默认输出格式:
- 时间和日期:毫秒级精度
- 日志级别:
ALL
,TRACE
,DEBUG
,INFO(默认级别)
,WARN
,ERROR
,FATAL
,OFF
(由低到高)
ALL
:打印所有日志
TRACE
:追踪框架详细流程日志,一般不使用
DEBUG
:开发调试细节日志
INFO
:关键、感兴趣信息日志
WARN
:警告但不是错误时的错误信息日志,比如:版本过时的
ERROR
:业务错误日志,比如出现各种异常
FATAL
:致命错误日志,比如JVM系统崩溃
OFF
:关闭所有日志记录
logback没有FATAL
级别,对应的是ERROR
- 进程ID
- --- :消息分隔符
- 线程名: 使用[]包含
- Logger名:通常是产生日志的类名
- 消息:日志记录的内容
1.2、使用application.properties/yml对日志进行输出配置
设置输出日志格式
#设置控制台输出日志格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss:SS} %-5level [%thread] %logger{15} ===> %msg%n
#2023-06-04 11:37:42:08 INFO [main] o.s.b.w.e.t.TomcatWebServer ===> Tomcat initialized with port(s): 8080 (http)
#一般使用下面这种
#格式化输出日志日期
logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss:SSS
设置日志级别
#默认所有日志没有精确指定级别就使用root的默认级别info
#logging.level.root=debug
#精确调整某个包下的日志级别
logging.level.com.atguigu.logging.controller=info
指定日志存储路径
SpringBoot默认将日志写在控制台,想要写在其它地方,则需在application.properties/yml中进行设置
logging.file.name | logging.file.path | 示例 | 效果 |
未指定 | 未指定 | 仅控制台输出 | |
指定 | 未指定 | my.log | 写入指定文件。可以加路径 |
未指定 | 指定 | D:/Desktop | 写入指定目录,文件名为spring.log |
指定 | 指定 | 以logging.file.name为准 |
#指定日志文件的路径,日志文件默认名叫spring.log
#logging.file.path=D:\\Desktop
#一般使用logging.file.name设置就足够
#指定日志文件的名: filename 和 path的配置同时存在只看filename
#1、只写名字,就生成到当前项目同位置的demo.log
#2、写名字+路径:生成到指定位置的指定文件
logging.file.name=my.log
文件归档与滚动切割
当我们程序运行产生的日志过多时,我们就会发现日志文件过大,打不开!找不到!诸如此类的情况,这时候我们就有必要对日志进行归档和切割了
归档:每天的日志单独存到一个文档中。
切割:每个文件10MB,超过大小切割成另外一个文件。
配置项 | 描述 |
logging.logback.rollingpolicy.file-name-pattern | 日志存档的文件名格式(默认值:${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz) |
logging.logback.rollingpolicy.clean-history-on-start | 应用启动时是否清除以前存档(默认值:false) |
logging.logback.rollingpolicy.max-file-size | 存档前,每个日志文件的最大大小(默认值:10MB) |
logging.logback.rollingpolicy.total-size-cap | 日志文件被删除之前,可以容纳的最大大小(默认值:0B)。设置1GB则磁盘存储超过 1GB 日志后就会删除旧日志文件 |
logging.logback.rollingpolicy.max-history | 日志文件保存的最大天数(默认值:7). |
#归档、切割
#日志文件的命名归档
logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz
#单个日志文件到达1MB,就进行文件的切割
logging.logback.rollingpolicy.max-file-size=1MB
示例:
1.3、切换日志框架
如果我们要引入其它框架?一定要把这个框架的默认日志依赖移除掉?
如何让系统中所有的日志统一到slf4j:
- 将系统的其它日志框架先排除出去
- 用中间包来替换原有的日志框架
- 我们导入sl4j来替换原有的日志框架
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
#把框架依赖的日志框架排除掉
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
SpringBoot能自动适配所有的日志,而且底层使用slf4j+logback的方式记录日志,引入其它框架的时候,只需要把这个框架依赖的日志框架排除掉。
2. 最佳实战
- 导入任何第三方框架,先排除它的日志包,因为Boot底层控制好了日志
- 修改
application.properties
配置文件,就可以调整日志的所有行为。如果不够,可以编写日志框架自己的配置文件放在类路径下就行,比如logback-spring.xml
,log4j2-spring.xml
- 如需对接专业日志系统,也只需要把 logback 记录的日志灌到 kafka之类的中间件,这和SpringBoot没关系,都是日志框架自己的配置,修改配置文件即可
- 业务中使用slf4j-api记录日志。不要再 sout 了