11 KiB
在构建任何应用程序时,良好的日志管理都是必不可少的。日志可以帮助我们监控、调试和跟踪代码的运行情况。 本小节中,我们继续完善 xiaohashu-auth 认证服务的项目骨架,为其整合 Logback 日志框架,并将配置日志的异步写入文件,以提升应用性能。
Tip
: 关于 Logback 理论介绍部分,可翻阅星球第一个项目 3.5 小节 ,这里不再赘述,直接上手实操。
1. 添加日志配置文件
编辑 xiaohashu-auth 认证服务,在 /resources 资源目录下,创建名为 logback-spring.xml 日志配置文件:
文件内容如下:
<configuration>
<!-- 引用 Spring Boot 的 logback 基础配置 -->
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<!-- 应用名称 -->
<property scope="context" name="appName" value="auth"/>
<!-- 自定义日志输出路径,以及日志名称前缀 -->
<property name="LOG_FILE" value="./logs/${appName}.%d{yyyy-MM-dd}"/>
<!-- 每行日志输出的格式 -->
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件的命名格式 -->
<fileNamePattern>${LOG_FILE}-%i.log</fileNamePattern>
<!-- 保留 30 天的日志文件 -->
<maxHistory>30</maxHistory>
<!-- 单个日志文件最大大小 -->
<maxFileSize>10MB</maxFileSize>
<!-- 日志文件的总大小,0 表示不限制 -->
<totalSizeCap>0</totalSizeCap>
<!-- 重启服务时,是否清除历史日志,不推荐清理 -->
<cleanHistoryOnStart>false</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 本地 dev 开发环境 -->
<springProfile name="dev">
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE"/> <!-- 输出控制台日志 -->
<appender-ref ref="FILE"/> <!-- 打印日志到文件中。PS: 本地环境下,如果不想打印日志到文件,可注释掉此行 -->
</root>
</springProfile>
<!-- 其它环境 -->
<springProfile name="prod">
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE"/> <!-- 生产环境下,仅打印日志到文件中 -->
</root>
</springProfile>
</configuration>
说一下日志配置文件中,每项配置都是干啥的:
- 基础配置和属性定义:
<include resource="org/springframework/boot/logging/logback/defaults.xml" />上述配置用于引用 Spring Boot 的默认 Logback 基础配置。
<property scope="context" name="appName" value="auth"/> <property name="LOG_FILE" value="./logs/${appName}.%d{yyyy-MM-dd}"/> <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
定义了一些全局属性:
appName:应用名称,这里值填写为auth,表示认证服务。
LOG_FILE:日志文件的路径和文件名模板,./logs表示输出到项目的同级目录下的/logs文件夹下。
LOG_PATTERN:日志输出格式。日志文件 Appender 配置:
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}-%i.log</fileNamePattern> <maxHistory>30</maxHistory> <maxFileSize>10MB</maxFileSize> <totalSizeCap>0</totalSizeCap> <cleanHistoryOnStart>false</cleanHistoryOnStart> </rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>${LOG_PATTERN}</pattern> <charset>UTF-8</charset> </encoder> </appender>
appender:用于将日志输出到文件,并且使用滚动策略来管理日志文件。
rollingPolicy:定义了日志滚动策略,使用SizeAndTimeBasedRollingPolicy以时间和大小为基准进行滚动。
fileNamePattern:定义了日志文件的命名模式。
maxHistory:保留 30 天的日志文件。
maxFileSize:每个日志文件最大 10MB。
totalSizeCap:总日志文件大小没有限制。
cleanHistoryOnStart:项目启动时不清理历史日志文件。
encoder:定义了日志的输出格式,以及文件编码格式。Spring Profile 配置:用于配置各环境的日志行为。这里主要定义了
dev和prod两个环境:<springProfile name="dev"> <include resource="org/springframework/boot/logging/logback/console-appender.xml" /> <root level="INFO"> <appender-ref ref="CONSOLE"/> <appender-ref ref="FILE"/> </root> </springProfile>
dev本地开发环境中,包含控制台输出CONSOLE和文件输出FILE。CONSOLE配置通过包含 Spring Boot 默认的console-appender.xml实现。<springProfile name="prod"> <include resource="org/springframework/boot/logging/logback/console-appender.xml" /> <root level="INFO"> <appender-ref ref="FILE"/> </root> </springProfile>
prod生产环境中,仅包含文件输出FILE,不输出到控制台。这是为了生产环境中减少控制台日志输出,避免影响性能。拓展小知识 : 如果你想同时设置多个环境,假设咱们除了本地开发环境、生产环境外,还有个
test测试环境, 也仅需要输出日志到文件。则可以配置如下,通过逗号,分隔开来就行:<springProfile name="test,prod"> // 省略... </springProfile>
2. 测试看看效果
因为我们上面通过 springProfile , 配置了 dev 开发环境中,打印日志到文件中。接下来,重启项目,实测一下看看功能是否正常:
项目启动成功后,如上图所示,进入到项目的 /logs 文件夹下,可以看到日志输出是 ok 的。
3. 异步日志
异步打印日志(Asynchronous Logging)是一种日志记录方式,它将日志写入操作放在一个单独的线程中执行,而不是在主线程中进行。这意味着日志写入的过程不会阻塞主线程的执行,主线程可以继续执行其余的业务逻辑,增强了应用的性能和响应速度。
3.1 为什么需要异步打印日志
-
性能提升:同步日志记录在高并发情况下会显著影响应用性能,因为每一次日志写入操作都可能导致磁盘 I/O 操作,主线程必须等待这些操作完成才能继续执行。异步日志记录将这些操作放在单独的线程中进行,避免了主线程的阻塞,提高了整体性能。
-
响应时间:异步日志记录可以减少应用的响应时间,尤其是在需要记录大量日志信息的时候。用户请求得到快速响应,而日志记录在后台处理。
-
资源利用:通过异步日志记录,应用可以更有效地利用 CPU 资源。同步日志记录可能导致线程频繁等待 I/O 操作完成,而异步记录可以让这些线程去执行其他任务,提高资源利用率。
-
系统稳定性:在极端情况下(例如,日志量非常大时),同步日志记录可能会导致应用出现性能瓶颈甚至崩溃。异步日志记录通过缓冲和队列机制,能够更好地应对突发的大量日志请求,增强系统稳定性。
3.2 Logback 配置异步日志
Logback 提供了 AsyncAppender 来支持异步日志记录。通过 AsyncAppender 可以将日志事件发送到一个队列中,并由一个独立的线程池来处理这些日志事件。编辑 logback-spring.xml 文件,添加配置如下:
// 省略...
<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
// 省略...
</appender>
<!-- 异步写入日志,提升性能 -->
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 是否丢弃日志, 0 表示不丢弃。默认情况下,如果队列满 80%, 会丢弃 TRACE、DEBUG、INFO 级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 队列大小。默认值为 256 -->
<queueSize>256</queueSize>
<appender-ref ref="FILE"/>
</appender>
<!-- 本地 dev 开发环境 -->
<springProfile name="dev">
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE"/> <!-- 输出控制台日志 -->
<appender-ref ref="ASYNC_FILE"/> <!-- 打印日志到文件中。PS: 本地环境下,如果不想打印日志到文件,可注释掉此行 -->
</root>
</springProfile>
<!-- 其它环境 -->
<springProfile name="prod">
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="ASYNC_FILE"/> <!-- 生产环境下,仅打印日志到文件中 -->
</root>
</springProfile>
// 省略...
解释一下修改的地方,主要添加了一个名称为
ASYNC_FILE异步输出日志的Appender:
AsyncAppender使用内部队列来异步处理日志事件。queueSize:队列的大小。discardingThreshold:是否丢弃日志, 0 表示不丢弃。最后,将各个环境中的
FILE更改为ASYNC_FILE异步写入日志。别忘了,再次重启一下项目,自测一波日志功能是否好使~