一:Spring Boot 日志
1.1 日志概述
日志对我们来说并不陌生,我们可以通过打印日志来发现和定位问题, 或者根据日志来分析程序的运行过程,但随着项目的复杂度提升, 我们对日志的打印也有了更高的需求, 而不仅仅是定位排查问题
比如有时需要记录⼀些用户的喜好等等. 但是 System.out.print 不能很好的满足我们的需求, 此时我们就需要使用⼀些专门日志框架
1.2 日志的用途
通过前面的学习, 我们知道日志主要是为了发现问题, 分析问题, 定位问题的, 但除此之外, 日志还有很多用途
- 系统监控
我们可以通过日志记录这个系统的运行状态, 每⼀个方法的响应时间, 响应状态等, 对数据进行分析, 设置不同的规则, 超过阈值时进星报警,比如统计日志中关键字的数量,并在关键字数量达到⼀定条件时报警
- 数据采集
数据采集是⼀个比较大的范围, 采集的数据可以作用在很多方面, 比如数据统计, 推荐排序等,下图中的数据源, 其中⼀部分就来自于日志记录的数据.
3. 日志审计
通过系统日志分析,可以判断⼀些非法攻击, 非法调用,还可以解决系统处理过程中的安全隐患.
1.3 日志使用
Spring Boot 项目在启动的时候默认就有日志输出,如下图所示:
SpringBoot 内置了日志框架 Slf4j , 我们可以直接在程序中调用 Slf4j 来输出日志
1.4 打印日志
打印日志的步骤:
- 在程序中得到日志对象.
- 使用日志对象输出要打印的内容
1.4.1 在程序中得到日志对象
在程序中获取日志对象需要使用日志工厂 LoggerFactory,如下代码所示:
private static Logger logger = LoggerFactory.getLogger(LoggerController.class);
LoggerFactory.getLogger 需要传递⼀个参数, 标识这个日志的名称. 这样可以更清晰的知道是哪个类输出的日志. 当有问题时, 可以更方便直观的定位到问题类
注意:Logger 对象是属于 org.slf4j 包下的, 不要导错包.
1.4.2 使用日志对象打印日志
日志对象的打印方法有很多种,我们可以先使用 info() 方法来输出日志,如下代码所示:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class LoggerController {private static Logger logger = LoggerFactory.getLogger(LoggerController.class);@RequestMapping("/logger")public String logger(){logger.info("--------------要输出日志的内容----------------");return "打印日志";}
}
这段代码的执行流程如下:
- 当请求到达 /logger 路径时,Spring框架会根据 @RequestMapping(“/logger”) 注解找到对应的处理方法 logger()。
- 接着 Spring 框架调用 logger 方法,该方法返回一个字符串 “打印日志”。
- 在 logger() 方法中,通过 LoggerFactory.getLogger(LoggerController.class) 获取了一个日志记录器对象 logger。
- 使用这个 logger 对象调用 info(),将日志消息--------------要输出日志的内容----------------"` 记录到日志中。
- 最后,方法返回字符串 “打印日志”,Spring 框架将其作为 HTTP 响应返回给客户端。
日志打印效果:
1.5 SLF4J 日志框架介绍
SLF4J 是门面模式的典型应用
SLF4J 不同于其他日志框架, 它不是⼀个真正的日志实现, 而是⼀个抽象层, 对日志框架制定的⼀种规范,所以 SLF4J 并不能独立使用, 需要和具体的日志框架配合使用.
1.6 门面模式
门面模式又称为外观模式, 它提供了⼀个统⼀的接口,用来访问子系统中的⼀群接口,其主要特征是定义了⼀个高层接口,让子系统更容易使用.
门面模式主要包含2种角色:
- 外观角色:也称门面角色,系统对外的统一接口.
- 子系统角色: 可以同时有⼀个或多个子系统.,每个子系统都不是⼀个单独的类,而是⼀个类的集合.,子系统并不知道门面角色的存在,对于子系统而言,门面角色只是另⼀个客户端而已,门面角色对子系统是透明的
举个例子:去医院看病可能要去挂号, 门诊, 化验, 取药, 这些流程可能会让患者或患者家属觉得很复杂, 但如果有提供接待人员, 只让接待人员来处理, 就变得很方便.
1.6.1 门面模式的实现
场景: 回家后我们会开各个屋的灯. 离开家时, 会关闭各个屋的灯,如果家里设置⼀个总开关, 来控制整个屋的灯就会很方便,我们使用门面模式的实现
public class FacadePatternDemo {public static void main(String[] args) {LightFacade lightFacade = new LightFacade();lightFacade.lightOn();}
}
/*** 灯的⻔⾯*/
class LightFacade{private Light livingRoomLight = new LivingRoomLight();private Light hallLight = new HallLight();private Light diningLight = new DiningLight();public void lightOn(){livingRoomLight.on();hallLight.on();diningLight.on();}public void lightOff(){livingRoomLight.off();hallLight.off();diningLight.off();}
}
interface Light {void on();void off();
}
/*** 客厅灯*/
class LivingRoomLight implements Light{@Overridepublic void on() {System.out.println("打开客厅灯");}@Overridepublic void off() {System.out.println("关闭客厅灯");}
}
/*** ⾛廊灯*/
class HallLight implements Light{@Overridepublic void on() {System.out.println("打开⾛廊灯");}@Overridepublic void off() {System.out.println("关闭⾛廊灯");}
}
/*** 餐厅灯*/
class DiningLight implements Light{@Overridepublic void on() {System.out.println("打开餐厅灯");}@Overridepublic void off() {System.out.println("关闭餐厅灯");}
}
门面模式的优点
- 减少了系统的相互依赖. 实现了客户端与子系统的耦合关系, 这使得子系统的变化不会影响到调用它的客户端;
- 提⾼了灵活性, 简化了客户端对子系统的使用难度, 客户端无需关心子系统的具体实现方式, 而只需要和门面对象交互即可.
- 提高了安全性. 可以灵活设定访问权限, 不在门面对象中开通方法, 就无法访问
1.7 SLF4J 框架介绍
SLF4J 就是其他日志框架的门面. SLF4J 可以理解为是提供日志服务的统⼀ API 接口, 并不涉及到具体的日志逻辑实现.
1.7.1 不引入日志门面
常见的日志框架有 log4J, logback 等. 如果⼀个项目已经使用了 log4j,而你还依赖另⼀个类库,假设这个类库是 Apache Active MQ, 它依赖于另外⼀个日志框架 logback, 那么你就需要把 logback 也加载进去.
存在问题:
- 不同日志框架的 API 接口和配置文件不同, 如果多个日志框架共存, 那么不得不维护多套配置文件
- 如果要更换日志框架, 应用程序将不得不修改代码, 并且修改过程中可能会存在⼀些代码冲突.
- 如果引如的第三方框架, 使用了多套, 那就不得不维护多套配置.
1.7.2 引入日志门面
引入门面日志框架之后, 应用程序只需要维护⼀套日志文件配置, 并且当底层实现框架改变时, 我们也不需要更改应用程序代码.
SLF4J 就是这个日志门面
1.8 日志格式的说明
我们之前打印的日志分别代表什么信息呢?
从上图可以看到,日志输出内容元素具体如下:
- 时间日期:精确到毫秒
- 日志级别:ERROR, WARN, INFO, DEBUG 或TRACE
- 进程ID
- 线程名
- Logger 名(通常使用源代码的类名)
- 日志内容
1.9 日志级别
日志级别代表着日志信息对应问题的严重性, 能够让我们更快的筛选符合目标的日志信息,日志的级别从高到低依次为: FATAL、ERROR、WARN、INFO、DEBUG、TRACE
- FATAL: 致命信息,表示需要立即被处理的系统级错误.
- ERROR: 错误信息, 级别较高的错误日志信息, 但仍然不影响系统的继续运行.
- WARN: 警告信息, 不影响使用, 但需要注意的问题
- INFO: 普通信息, 用于记录应用程序正常运行时的⼀些信息, 例如系统启动完成、请求处理完成等.
- DEBUG: 调试信息, 需要调试时候的关键信息打印.
- TRACE: 追踪信息, 比 DEBUG 更细粒度的信息事件(除非有特殊用意,否则请使用DEBUG 级别替代)
1.10 日志级别的使用
日志级别是开发人员自己设置的. 开发人员根据自己的理解来判断该信息的重要程度,针对这些级别, Logger 对象分别提供了对应的方法, 来输出日志.
/*** 打印不同级别的⽇志* @return*/
@RequestMapping("/printLog")
public String printLog() {logger.trace("================= trace ===============");logger.debug("================= debug ===============");logger.info("================= info ===============");logger.warn("================= warn ===============");logger.error("================= error ===============");return "打印不同级别的⽇志" ;
}
观察打印的日志结果:
结果发现, 只打印了 info, warn 和 error 级别的日志,这与日志级别的配置有关, 日志的输出级别默认是 info 级别, 所以只会打印大于等于此级别的日志, 也就是 info, warn 和 error,fatal 就没必要打印了,因为是致命信息。
1.11 日志配置
1.11.1 配置日志级别
日志级别配置只需要在配置文件中设置 “logging.level” 配置项即可,如下所示:
- Properties 配置
logging.level.root: debug
- yml配置
logging:level:root: debug
properties 和 yml 只需要配置其中⼀个即可.
重新运行上述代码, 观察结果:
1.11.2 日志持久化
以上的日志都是输出在控制台上的, 然而在线上环境中, 我们需要把日志保存下来, 以便出现问题之后追溯问题. 把日志长久保存下来就叫持久化.
日志持久化有两种方式:
- 配置日志文件名
- 配置日志的存储目录
1.11.2.1 配置日志文件名
- Properties 配置
logging.file.name: logger/springboot.log
- yml 配置
# 设置⽇志⽂件的⽂件名
logging:file:name: logger/springboot.log
运行结果显示, 日志内容保存在了对应的目录下:
1.11.2.2 配置日志的存储目录
- Properties 配置
logging.file.path: D:/temp
- yml 配置
# 设置⽇志⽂件的⽬录
logging:file:path: D:/temp
运行程序, 该路径下多出⼀个日志⽂件: spring.log
注意: logging.file.name 和 logging.file.path 两个都配置的情况下, 只有 logging.file.name 生效
1.11. 3 配置日志文件分割
如果我们的日志都放在⼀个文件中, 随着项目的运行, 日志文件会越来越大, 需要对日志文件进行分割.(默认情况下日志文件超过 10M 就进行分割)
配置项 | 说明 | 默认值 |
---|---|---|
logging.logback.rollingpolicy.file-name-pattern | 日志分割后的文件名格式 | ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz |
logging.logback.rollingpolicy.max-file-size | 日志文件超过这个大小就自动分割 | 10MB |
- Properties 配置
logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}.%i
logging.logback.rollingpolicy.max-file-size=1KB
- yml 配置
logging:logback:rollingpolicy:max-file-size: 1KBfile-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i
- 日志文件超过 1KB 就分割(设置 1KB 是为了更好展示. 企业开发通常设置为 200M, 500M 等)
- 分割后的日志文件名为: 日志名.日期.索引
项目运行, 多打印⼀些日志, 日志分割结果:
1.11.4 配置日志格式
目前日志打印的格式是默认的:
打印日志的格式, 也是支持配置的. 支持控制台和日志文件分别设置,配置日志格式我们通常使用 logging.pattern.console 和 logging.pattern.file 这两个配置项,下面我们来详细说说
1.11.4.1 logging.pattern.console
logging.pattern.console 用于控制台日志格式,它的默认值为:
%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH: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}
第一个参数:
%clr
: 完整语法是:%clr(表达式){颜色} 这个部分可能表示设置日志级别的颜色。在许多日志系统中,可以通过颜色来突出显示不同级别的日志消息,比如红色表示错误,黄色表示警告,绿色表示信息,等等,因为代码有很多重复,接下来将不再讲解这个知识点
支持颜色有以下几种:
- blue(蓝色)
- cyan(青色)
- faint(淡色)
- green(绿色)
- magenta(品红色)
- red(红色)
- yellow(黄色)
%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}
: 这是用于格式化日期的部分。%d
: 这是一个占位符,用于指示要格式化的日期和时间。${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}
: 这是一个用于指定日期格式的模式。在这里,${LOG_DATEFORMAT_PATTERN:-}
是一个占位符,它的含义是如果环境变量LOG_DATEFORMAT_PATTERN
存在,则使用它作为日期格式的模式;否则,使用默认模式yyyy-MM-dd'T'HH:mm:ss.SSSXXX
。这个模式中包含了以下元素:yyyy
: 年份,比如 2022、2023 等等。MM
: 月份,使用两位数表示,比如 01 表示一月,02 表示二月,以此类推。dd
: 日期,使用两位数表示,比如 01 表示一号,02 表示二号,以此类推。'T'
: 字符 ‘T’,可能用于表示日期和时间之间的分隔符。HH
: 小时,使用两位数表示,24 小时制,比如 00 表示午夜零点,01 表示凌晨一点,以此类推。mm
: 分钟,使用两位数表示,比如 00 表示整点,01 表示一分,以此类推。ss
: 秒,使用两位数表示,比如 00 表示整秒,01 表示一秒,以此类推。SSS
: 毫秒,使用三位数表示,比如 000 表示整毫秒,001 表示一毫秒,以此类推 -XXX
: 时区偏移,表示与 UTC 时间的偏移量。例如,-07:00
表示比 UTC 时间晚七个小时的时区。
第二个参数:
-
${LOG_LEVEL_PATTERN:-%5p}
: 这个部分是一个环境变量的占位符,用于指定日志级别的格式。如果环境变量LOG_LEVEL_PATTERN
已经设置,那么就会使用它的值。如果没有设置,则使用默认值%5p
。-
${LOG_LEVEL_PATTERN:-}
: 这个部分表示一个环境变量的默认值的语法。在这种语法中,如果LOG_LEVEL_PATTERN
环境变量存在,则将其值插入到这里;否则,使用默认值。 -
%5p
: 这是日志级别的占位符。p
代表显示日志级别 ERROR,MARN,INFO,DEBUG,TRACE。数字5
表示固定宽度格式化,即每个日志级别将占用 5 个字符的宽度。
-
例如,如果日志级别是 INFO
,且使用 %5
的格式化,则输出将是 " INFO"
,以确保每行日志的日志级别部分对齐。这在查看日志时有助于提高可读性。
第三个参数:
${PID:- }
的含义是,如果环变量PID
存在,则使用它的值作为进程ID;否则,使用空格替。这样设计的目的是在没有明确指定 PID 的情况下,使志保持整洁可读。
第四个参数:
这个参数 %clr(---){faint}
是一个用于设定日志输出样式和格式的表达式。
---
:这是要显示的文本。在这种情况下,文本是三个连字符,可能用作日志中的分隔线或者标记。
第五个参数:
这个参数 %clr([%15.15t]){faint}
是一个用于设定日志输出样式和格式的表达式。
[%15.15t]
:15.15:这是时间戳格式化的规则,指了时间戳字符串的长度。在这种情况下,两个数字分别表示最小和最大的字符数限制。因此,15.15 意味着时间戳的长度被限制在15个字符。如果时间戳长度不足15个字符,则会在前面填充空格,如果超过15个字符会进行截断。
第六个参数:
这个参数 %clr(%-40.40logger{39}){cyan}
是用于设定日志输出样式和格式的表达式,
(%-40.40logger{39})
: 这部分指定日志消息的格式或布局。-40.40
: 这可能是一个指定字段宽度的格式说明符。这里的-40
可能表示该字段的最小宽度为 40 个字符,40
可能表示最大宽度也为 40 个字符。这可以确保字段的对齐和格式整齐。logger{39}
: 这部分可能是在字段中指定要填充的内容。在这种情况下,logger
可能表示日志记录器的名称或标识符,而{39}
则表示填充的内容是由长度为 39 的字符串表示的,即使日志记录器本身不到 39 个字符,通过填使其达到指定的宽度,可以确保日志输出的格式整齐,易于阅和理解。
第七个参数:
这个参数 %clr(:){faint}
是用于设定日志输出样式和格式的表达式,
%clr(:)(faint}
:这部分主要用于设置日志输出中冒号的样式。
第八个参数:
%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
这个参数是与日志记录相关的配置项
-
%m
: 这个标记代表了日志消息。在日志中,通常会包含一条消息,用描述事件、错误或者其他需要记录的信息。m标记表示该位置被替换为日志消息。 -
%n
: 这个标记代表了换行符,为了更好地阅读和解析 -
%w
: 这个标记代表了异常信息。%w标记表示该位置将被替换为异常信息。 -
%Ex
: 这个标记代表了异常的堆跟踪。,%Ex标记表示该位置将被替换为异常的堆栈跟踪信息。 -
LOG_EXCEPTION_CONVERSION_WORD
: 这个部分表示一个环境变量的默认值的语法。在这种语法中,如果LOG_EXCEPTION_CONVERSION_WORD
环境变量存在,则将其值插入到这里;否则,使用默认值。
1.11.4.2 logging.pattern.file
logging.pattern.file 用于控制日志文件的日志格式,它的默认值为:
%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}
${LOG_LEVEL_PATTERN:-%5p}
${PID:- }--- [%t]
%-40.40logger{39} :
%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
让我们逐段解释它:
第一个参数:
-
%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}
: 这部分定义了日期格式。%d
表示日期时间,${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}
指定了日期的格式。如果环境变量LOG_DATEFORMAT_PATTERN
未定义,则默认使用yyyy-MM-dd'T'HH:mm:ss.SSSXXX
格式。 -
y
: 年份,表示年份的数字。例如,2024年将被表示为"2024"。 -
M
: 月份,月份的数字。例如,4月份将被表示为"04"。 -
d
: 日期,表示日期的数字。例如,29号将被表示为"29"。 -
'T'
: 字符 ‘T’,它用于分隔日期和时间部分,通常在ISO 8601格式中使用。 -
H
: 小时,表示小时的数字(24小时制)。例如,晚上11点将被表示为"23"。 -
m
: 分钟,表示分钟的数字。例如,33分钟将被表示为"33"。 -
s
: 秒,表示秒数的数字。例如,54秒将被表示为"54"。 -
S
: 毫秒,表示毫秒数的数字。例如,123毫秒将表示为"123"。 -
X
: 时区,表示时区的偏移量。例如,东八区北京时间)将被表示为"+08:00"。
第二个参数:
-
${LOG_LEVEL_PATTERN:-%5p}
: 这部分定义了日志级别格式。${LOG_LEVEL_PATTERN:-%5p}
指定了日志级别的格式。如果环境变量LOG_PATTERN
未定义,则默认使用%5p
,它表示日志级别的最小宽度为5个字符,右对齐。 -
${LOG_LEVEL_PATTERN}
:这是一个环境变量,用于指定日志级别的输出格式 -
:-
:这是一个默认值分隔符,用于指定当环境变量未设置时所采用的默认值。 -
%5p
:这是实际的日志级别格式。-
%p
:这是日志级别的占位符。它会被替换为实际的日志级别。表示显示日志级别 ERROR,MARN,INFO,DEBUG,TRACE. -
%5p
:这表示日志级别的最小宽度为5个字符如果实际的日志级别的字符数少于5个,将会在左侧填充空格,使其达到5个字符宽度。如果超过个字符,则保持原样输出。
-
第三个参数:
${PID:- }--- [%t] :
用于定义日志记录中的进程ID、线程名。
-
${PID:- }
:这个部分定义了进程ID的输出格式。${PID}
是一个环境变量,它表示进程ID。如果环境变量PID
被设置了值(比如一个进程的实际ID),那么它将被替换为这个值;如果未设置,则会输出一个空格,这里的冒号:
表示了进程ID结束的标志。 -
---
:这个部分是一个分隔符,用于分隔进程ID和线程名。 -
[%t]
:这个部分定义了线程名的输出格式。%t
是一个占位符,表示线程名。通常,线程名是指当前执行线程的名称。方括号[]
用于包裹线程名,以区分它与其他日志信息。例如,[main]
表示主线程。
第四个参数:
-
%-40.40logger{39}:
:这个部分定义了日志记录器名称的输出格式。-
%-40
: 这表示日志记录器名称的最小宽度为40个字符。如果日志记录器名称的长度不足40个字符,将会在右侧用空格填充,以达到40个字符的宽度。 -
.40
: 这表示日志记录器名称的最大宽度为40个字符。如果日志记录器名称的长度超过40个字符,将会被截断,只保留前40个字符,并在末尾添加省略号以表示截断。 -
logger
: 这是日志记录器名称的占位符。在实际的日志记录中,这个占位符会被替换为实际的日志记录器名称。 -
{39}
:这部分指定了在无法确定日志记录器名称长度时显示的字符数。在这个例子中,如果日志记录器名称的长度无法确定,将会显示39个字符。
-
-
:
:这个部分是一个隔符,用于分隔日志记录器名称和日志消息。
第五个参数:
-
%m%n
这个参数是用来定义日志消息格式的-
%m
是一个占位符,表示日志消息。在实际的日志记录中,这个占位符会被替换为实际的日志消息内容。 -
%n
是一个转义符,表示换行符。它用于在每条日志消息之后添加一个换行,以使日志输出更易读。
-
所以%m%n
保证了每条日志消息输出后都会有一个换行符。
-
${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
用来指定在记录日志时发生异常时如何转换异常信息的格式。这个参数可以分为两个部分来理解${LOG_EXCEPTION_CONVERSION_WORD}
和:-%wEx
。-
${LOG_EXCEPTION_CONVERSION_WORD}
:这部分是一个环境变量或者参数的引用,它表示如果LOG_EXCEPTION_CONVERSION_WORD
这个环境变量被设置了,就使用其所指定的值;如果没有设置,就使用默认值。 -
:-%wEx
这部分是一个默认设定,如果环变量LOG_EXCEPTION_CONVERSION_WORD
没有被设置,则使用该默认值。:-
表示如果环境变量没有设置,则采用后面的值。
-
现在让我们更详细地解释一下 %wEx
这个默认值的含义:
-
%w
:这个占位符表示异常的引发位置(where)。在记录日志时,它会被替换为异常发生的位置信息,比如文件名、行号等。这可以帮助开发者追踪异常发生的具体位置,从而更容易地进行调试和排查问题。 -
E
:这个占位符表示异常的类型(exception)。在记录日志时,它会被替换为异常的类型,比如错误的类型名或者错误代码。 -
x
:这个占位符表示异常的详细信息(extra)。在记录日志时,它会被替换为异常的详细描述,通常包括异常的消息、堆栈跟踪等。
1.11.5 设置了颜色, 却没有生效的问题
此时我们需要配置, 让 idea 支持控制台颜色显示
- 打开启动配置, 添加 VM options
- 添加 VM options -Dspring.output.ansi.enabled=ALWAYS
- 重新启动程序, 就发现控制台支持颜色了
1.11.6 修改日志的默认格式
下面举一个简单的代码例子来修改日志的默认格式
- Properties 配置
logging.pattern.console='%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
- yml 配置
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'
-
%d{yyyy-MM-dd HH:mm:ss.SSS}
: 这是日期时间的格式化字符串,其中%d
表示输出日期时间,{}
中的内容yyyy-MM-dd HH:mm:ss.SSS
则规定了日期时间的显示格式为年-月-日 时:分:秒.毫秒。 -
%c
: 这个标记代表了日志记录器(Logger)的名称。在日志中,Logger 通常用于标识记录日志的组件或类。 -
%M
: 这个标记代表了调用日志记录器的方法名。它记录了日志记录发生的位置,即调用日志记录语句的方法名。 -
%L
: 这个标记代表了日志记录发生的行号。它记录了日志记录语句在源代码中的行号。 -
[%thread]
: 这个标记代表了线程名,用于记录日志记录发生时所处的线程。 -
%m
: 这个标记代表了日志消息。它记录了需要被记录的具体信息。 -
%n
: 这个标记代表了换行符。在日志中,为了更好地阅读和解析,通常会在不同的日志条目之间插入换行符。
项目运行, 观察日志变化:
通常情况下, 咱们就使用默认的日志格式打印即可.
1.11.7 更简单的日志输出
每次都使用 LoggerFactory.getLogger(xxx.class) 很繁琐, 且每个类都添加⼀遍, lombok 给我们提供了⼀种更简单的方式
- 添加 lombok 框架支持
- 使⽤ @slf4j 注解输出日志。
1.11.7.1 添加 lombok 依赖
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
1.11.7.2 输出日志
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;@Slf4j
@RestController
public class LogController {public void log(){log.info("--------------要输出⽇志的内容----------------");}
}
这段代码的执行流程如下:
-
导入库和注解:
import lombok.extern.slf4j.Slf4j;
: 导入 Lombok 的@Slf4j
注解import org.springframework.web.bind.annotation.RestController;
: 导入 Spring Framework 的@RestController
注解
-
类定义:
@Slf4j
: 这个注解告诉 Lombok 自动生成一个名为log
的 Logger 对象,可以在类中直接使用。@RestController
: 用于处理 HTTP 请求并返回响应。
-
方法定义:
log.info("--------------要输出⽇志的内容----------------");
: 在log
方法中调用 Logger 的info
方法,输出一条信息到日志中。
-
执行流程:
- 当这个类被实例化,并且调用了
log()
方法时,会执行方法体内的代码。 - 在
log()
方法内部,使用了log.info()
方法,表示以 INFO 级别记录一条日志信息。 - 由于使用了 Lombok 的
@Slf4j
注解,因此无需手动创建 Logger 对象,可以直接使用log
对象来记录日志。 - 这条日志信息会根据日志配置的格式(如前面提到的
logging.pattern.console
或logging.pattern.file
)被输出到相应的日志文件或控制台中。
- 当这个类被实例化,并且调用了