Java EE 进阶:7.Spring Boot 日志(第二弹)
目录2.5 日志配置2.5.1 配置日志级别分目录/路径设置级别2.5.2 日志持久化配置日志文件的路径和文件名配置日志文件的保存路径2.5.3 配置日志文件分割2.5.4 配置日志格式3.更简单的日志输出3.1 添加 Lombok 依赖3.2 输出日志4.总结书接上文Java EE 进阶7.Spring Boot 日志第一弹~~2.5 日志配置上述是日志的使用, 日志框架支持我们更灵活的输出日志, 包括内容, 格式等.2.5.1 配置日志级别日志级别配置只需要在配置文件中设置logging.level配置项即可如下所示后面课程中出现的配置, properties 和yml只需要配置其中一个即可.二者转换方式: Properties文件的点( . ) 对应yml文件中的换行以下两个配置, 根据项目使用其中之一.Properties配置logging.level.rootdebugyml配置咱们手动调整成 tarce 级别logging: level: root: trace这个 root 就是根目录的意思~~对于所有目录都生效所有目录都是 trace 级别重新运行上述代码, 观察结果我们发现此时日志就变得特别细了甚至创建一个对象都跟你说而我们打印的日志就在这里找不到的话就右键全部清空然后再访问 http://127.0.0.1:8080/log/print分目录/路径设置级别那我现在又有需求了我只想看我自己打印的 tarce 级别的日志其他的那些日志我都不想看咋办上面我们说 root 是根目录那么这时候就用到分目录了logging: level: root: info com: bit: log: controller: trace此时我们发现 Spring 那些低于 info 的就不打印了没有那么多了同时还把我们需要的 trace 和 debug 打印出来了答疑Q1之前讲的验证码那个 session 的 key 写死了那多个用户请求验证码是不是会有错误先说一下不会报错的这就又需要我们 Session 相关的知识了一句话Session 是存储用户信息的会话机制自然能分辨出不同的用户信息~~所以说 Session 本身就是分用户的我们的 Tomcat 就是咱们一直用的 IDEA 的 Web 服务器本身就是多线程的所以我们不用取考虑这用户过来的时候什么样当我们运行项目的时候Tomcat 就会从线程池中拿一个线程给我们跑所以这个线程的安全性是我们的服务器本身就给我们保证了的所以这里分两个都给我们了保证Session 本身的机制就保证了各个用户的隔离性SessionId 已经帮我们区分好了服务端帮我们做的下面给大家演示一下RequestMapping(/captcha) RestController public class CaptchaController { private static final Logger logger LoggerFactory.getLogger(CaptchaController.class); Autowired//把配置文件的内容注入进来 //…… logger.info(getCaptcha cost time:(end-start)ms); } /** * 验证用户输入的验证码是否正确 * param captcha用户输入的验证码 * param session * return false:校验失败,true:验证成功 */ //…… }然后多请求几次此时我们就能发现服务端已经帮我们创建多线程了所以请求过来的时候Tomcat 是去线程池中去拿线程的已经帮我们做好了咱们无需考虑当然如果是你自己写的你就需要考虑了~~有同学一开始说给定义在上面像这个一样那这时候就可能有问题了因为这个 static 本身意思就是大家共享的了所以我们要引入 Session~~Q2现在面试的时候日志这里问的多吗现在问的不多了因为日志现在也越来越好用了15年前问的多15年前大家都用的 log4j 和 logback用着是非常麻烦的日志老是出问题要么就是项目启动了但是没日志~~注意 log4j 念 log Four j而不是数字 4说出去让人家笑话~~闲聊校招VS社招校招校园招聘只针对在校学生社招社会招聘在校学生社会人士猎聘、智联、BOSS直聘这都属于社招我们可以直接在网上搜索校园招聘比如字节的这就是只针对在校学生字节跳动校园招聘官网字节跳动校招其中大四或者即将大四毕业走应届生招聘大一、大二、大三走实习生招聘~~但是校招相对社招来说会多一点点Q高中生能招吗一般是不招的高中招的话只能是小时工或者兼职但是学历在咱们这还是比较看重的大公司更是在意因为他们认为基础知识是可以培养的但是一个人的先天的智商培养不出来所以更喜欢问一些场景题来考察思维社招的话场景提问就比较少了社招主要看你以往的公司、工作经验工作时间越长就越不看你学校了工作个十年可以说学历这个滤镜就彻底没有了~~当然我们投简历的时候先投小公司练练手挂了也无所谓因为大公司都是有面试记录的甚至连几年前甚至问了你什么你的态度……都会有记录的~~所以日志这里大家会用就行了日志就不用准备面试了~~2.5.2 日志持久化以上的日志都是输出在控制台上的, 然而在线上环境中, 我们需要把日志保存下来, 以便出现问题之后追溯问题. 把日志保存下来就叫持久化.日志持久化有两种方式1. 配置日志文件名2. 配置日志的存储目录这个图片取自Common Application Properties :: Spring Boot配置日志文件的路径和文件名Properties配置logging.file.namelog.logyml配置# 设置日志文件的文件名 logging: file: name: log.log注意我们官方文档和课件中给的配置都是从最左边给大家提供的所以要稍微修改一下logging: level: root: info com: bit: log: controller: trace file: name: log.log运行程序后刷新一下就会在左边多了一个日志文件而这个日志文件就会持久记录我们的日志形式是追加的~~后面可以跟绝对路径或者相对路径下面我们来写一下相对路径logging: level: root: info com: bit: log: controller: trace file: name: log/log.log重启服务后还是相同的刷新方法然后就会发现在这里多了一个 log 文件夹里面就是日志文件把刚才启动的日志存储在这里了配置日志文件的保存路径为了方便观察我们把上述两个日志文件全部删掉再来测试Properties配置logging.file.pathD:/tempyml配置# 设置日志文件的目录 logging: file: path: D:/temp上述是课件的绝对路径我们现在配置相对路径logging: level: root: info com: bit: log: controller: trace file: # name: log/log.log path: logger/运行服务后刷新发现加载出来了已经放在我们的硬盘上了那我们能不能像上面一样把名称也配置上呢下面来测试一下依旧把刚刚的日志文件删掉方便观察logging: level: root: info com: bit: log: controller: trace file: # name: log/log.log path: logger/log.log运行服务后刷新我们发现并不能log.log 变成了一个文件夹它认为这是一个文件夹因为这是配置路径的所以只能为路径不能为文件这种方式只能设置日志的路径, 文件名只能为 spring.log不能修改名称那么我们现在就知道了file.name可以配置名称可以带绝对路径或相对路径file.path可以配置路径那么我一个配置的 log一个配置的 logger到底用哪个logging: level: root: info com: bit: log: controller: trace file: name: log/log.log path: logger依旧删除旧日志文件重启服务后刷新观察结果我们发现 log.log 生效了~~那是不是因为 log.log 写在了 logger/ 上面才生效呢我们把它俩互换一下位置再来测试logging: level: root: info com: bit: log: controller: trace file: path: logger name: log/log.log我们发现还是 log.log 生效了这说明logging.file.name 和 logging.file.path 两个都配置的情况下, 只生效其一, 以 logging.file.name 为准那么现在我们又有疑问了既然一个是配置路径一个是配置名称那我能不能这么写把 log.log 文件放在 logger 文件夹下面呢logging: level: root: info com: bit: log: controller: trace file: path: logger name: log.log依旧删除旧日志文件重启服务后刷新观察结果我们发现这是不可以的也就是说logging.file.name 和 logging.file.path 同时存在时logging.file.path 是完全不生效的~~2.5.3 配置日志文件分割我们上面也说了这种日志是追加的方式如果我们的日志都放在一个文件中, 随着项目的运行, 日志文件会越来越大, 需要对日志文件进行分割.当然, 日志框架也帮我们考虑到了这一点, 所以如果不进行配置, 就走自动配置默认日志文件超过10M就进行分割配置项说明默认值logging.logback.rollingpolicy.file-name-pattern日志分割后的文件名格式${LOG_FILE}.%d{yyyy-MM-dd}.%i.gzlogging.logback.rollingpolicy.max-file-size日志文件超过这个大小就自动分割10MB配置日志文件分割下面我们按 1KB 尝试分割为了日志内容多一些把日志级别改为 tarcelogging: level: root: trace com: bit: log: controller: trace file: # path: logger name: logger/log.log logback: rollingpolicy: max-file-size: 1KBlogback 大家应该不陌生了这个是一个日志框架因为我们的 slf4j 或者 Spring 都是对 logback 进行封装里面的包括这些配置也都是 logbcak 的配置1. 日志文件超过1KB就分割(设置1KB是为了更好展示. 企业开发通常设置为200M, 500M等, 此处没有明确标准)2. 分割后的日志文件名为: 日志名.日期.索引项目运行, 多打印一些日志, 日志分割结果打开查看确实每个都是 1KB随便打开一个可以发现里面就是日志的内容上面文件的命名格式对应着file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz${LOG_FILE}定义的日志名称%d日期{yyyy-MM-dd}日期格式%i序号gz文件格式如果说刚刚生成的文件名不合适那么我还可以设置一个文件名称比如把 .gz 去掉这样打开方便点能避免解压logging: level: root: trace com: bit: log: controller: trace file: # path: logger name: logger/log.log logback: rollingpolicy: max-file-size: 10KB file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i可以看到这次不用解压就能打开了注意这个日志分割不是严格的 10KB而是按行为单位来起码把这一行日志给你打印完整才会分割的比如我们接下来设置成 1字节直接改为 1Blogging: level: root: info com: bit: log: controller: trace file: # path: logger name: logger/log.log logback: rollingpolicy: max-file-size: 1B file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i运行后我们随便打开一看基本上都是一行一个日志而文件大小显然已经超过了 1B所以说 1B 可以说根本就设置不上的~~2.5.4 配置日志格式目前日志打印的格式是默认的打印日志的格式, 也是支持配置的. 支持控制台和日志文件分别设置配置项说明默认值logging.pattern.console控制台日志格式%clr(%d${LOG_DATEFORMAT_PATTERN:-yyyy-MM-ddTHH:mm:ss.SSSXXX}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:-}){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}logging.pattern.file日志文件的日志格式%d${LOG_DATEFORMAT_PATTERN:-yyyy-MM-ddTHH:mm:ss.SSSXXX} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}配置项说明:上面这个默认值是旧的大家了解即可1. %clr(表达式){颜色} 设置输入日志的颜色支持颜色有以下几种:• blue• cyan• faint• green• magenta• red• yellow2. %d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-ddTHH:mm:ss.SSSXXX}} 日期和时间--精确到毫秒%d{} 日期${LOG_DATEFORMAT_PATTERN:-yyyy-MM-ddTHH:mm:ss.SSSXXX} 非空表达式, 获取系统属性LOG_DATEFORMAT_PATTERN , 若属性 LOG_DATEFORMAT_PATTERN 不存在则使用 -yyyy-MM-dd HH:mm:ss.SSSXXX 格式, 系统属性可以System.getProperty(LOG_DATEFORMAT_PATTERN) 获取3. %5p 显示日志级别ERRORMARNINFODEBUGTRACE.4. %t 线程名. %c 类的全限定名. %M method. %L 为行号. %thread 线程名称. %m 或者%msg 显示输出消息. %n 换行符5. %5 若字符长度小于5则右边用空格填充. %-5 若字符长度小于5则左边用空格填充. %.15 若字符长度超过15截去多余字符. %15.15 若字符长度小于15则右边用空格填充. 若字符长度超过15截去多余字符更多说明, 参考:Chapter 6: Layouts设置了颜色, 却没有生效?需要配置, 让idea支持控制台颜色显示运行程序找到这个1. 打开启动配置, 添加VM options2. 添加VM options -Dspring.output.ansi.enabledALWAYS3. 重新启动程序, 就发现控制台支持颜色了日志级别不同颜色也不同~~Properties配置logging.pattern.console%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%nyml配置logging: pattern: console: %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n file: %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n总的 yml logging: level: root: info com: bit: log: controller: trace file: # path: logger name: logger/log.log logback: rollingpolicy: max-file-size: 10MB file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i pattern: console: %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n file: %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n启动服务后重新访问一下网页调用一下接口观察日志变化可以看到此时我们自定义的日志格式就生效了格式日期时间类print打印的行线程名称日志换行通常情况下, 咱们就使用默认的日志格式打印即可.3.更简单的日志输出package com.bit.log.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Created with IntelliJ IDEA. * Description: * User: CoderYanger * Date: 2026-11-02 * Time: 19:37 */ RequestMapping(/log) RestController public class LogController { private static Logger logger LoggerFactory.getLogger(LogController.class); RequestMapping(/print) public String print(){ System.out.println(sout打印日志); logger.info(logger 打印日志); logger.trace(logger trace...); logger.debug(logger debug...); logger.info(logger info...); logger.warn(logger warn...); logger.error(logger error...); //Logger没提供fatal因为也用不上问题太大也没必要看日志了~~ return 打印日志; } }上述代码的这一行private static Logger logger LoggerFactory.getLogger(LogController.class);默认打印的就是 LogController.class全限定名称路径类名如果我们改成 aaaaprivate static Logger logger LoggerFactory.getLogger(aaaa);那么打印的就是 aaaa但是我们基本是不会改的因为一改就不知道这是个啥了所以这一行默认就是固定的~~每次都使用 LoggerFactory.getLogger(xxx.class) 很繁琐, 且每个类都添加一遍, lombok给我们提供了一种更简单的方式.1. 添加 lombok 框架支持2. 使用 slf4j 注解输出日志。3.1 添加 Lombok 依赖dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency3.2 输出日志Slf4j RequestMapping(/log2) RestController public class LogController2 { RequestMapping(/print) public String print(){ System.out.println(sout打印日志); log.info(logger 打印日志); log.trace(logger trace...); log.debug(logger debug...); log.info(logger info...); log.warn(logger warn...); log.error(logger error...); return 打印日志; } }注意此处路径映射为 log2不能与刚刚的 log 重复否则会路径映射错误引起报错~~lombok提供的Slf4j 会帮我们提供一个日志对象 log, 我们直接使用就可以.启动服务后重新调用一下接口再来查看日志我们接下来来看它的原理是什么以后我们打印日志直接用这个来自 Lombok 的注解就可以了~~4.总结1. 日志是程序中的重要组成部分使用日志可以快速的发现和定位问题Spring Boot 内容了日志框架默认情况下使用的是 info 日志级别将日志输出到控制台的我们可以通过 lombok 提供的Slf4j 注解和 log 对象快速的打印自定义日志.2. 日志包含 6 个级别, 日志级别越高收到的日志信息也就越少我们可以通过配置日志的保存名称或保存目录来将日志持久化.