在现代软件开发中,日志记录是系统监控和故障排查的重要工具。尤其是随着微服务架构的流行,日志的复杂性和数量都有了显著的增加。结构化日志(Structured Logging)因为其易于解析和分析而变得越来越流行。然而,对于开发者和运维人员来说,结构化日志的可读性可能不如传统的文本日志。那么,我们如何在保持结构化日志的优势的同时,又能提供一种更适合人类阅读的日志格式呢?
结构化日志的挑战
结构化日志通常以JSON格式记录信息,例如:
{"@timestamp":"2024-03-24T23:03:13.693+08:00","@version":"1","message":"Release executor io.netty.channel.nio.NioEventLoopGroup@1e499f1","logger_name":"io.lettuce.core.resource.DefaultEventLoopGroupProvider","thread_name":"SpringApplicationShutdownHook","level":"DEBUG","level_value":10000}这种格式虽然机器解析起来非常方便,但对于人类来说阅读起来并不直观。例如,我们希望看到的格式可能是:
【2024-03-24T23:03:13.693+08:00】 【SpringApplicationShutdownHook】io.lettuce.core.resource.DefaultEventLoopGroupProvider【DEBUG】: Release executor io.netty.channel.nio.NioEventLoopGroup@1e499f1解决方案
在Spring Boot应用中,我们可以使用application.yml文件来配置日志格式,从而实现双重日志输出:
1. 配置application.yml
logging:level:root:debugfile:name:human.logpattern:file:"[%d{yyyy-MM-dd'T'HH:mm:ss.SSSz}] [%t] %class [%p]: %msg%n"这种配置会生成一个名为human.log的文件,其中的日志将按照上述格式记录。
2. 日志示例
假设我们有一个简单的Spring Boot应用,以下是它运行后在human.log中的日志示例:
[2024-05-21T09:45:32.576EST] [main] example.feature.Hello [DEBUG]: example message3. 代码实现
为了确保日志同时以结构化和人类可读的格式输出,我们可以在日志配置中定义多个文件:
logging:level:root:debugfile:name:app.log# 结构化日志文件pattern:file:'%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n'loggers:com.example:level:DEBUGfile:name:human.log# 人类可读日志文件pattern:file:"[%d{yyyy-MM-dd'T'HH:mm:ss.SSSz}] [%t] %class [%p]: %msg%n"结论
通过配置Spring Boot的日志系统,我们可以实现结构化日志和人类可读日志的双重输出。这种方式不仅保留了结构化日志的所有优势,还提供了更友好的阅读体验,使得开发和运维工作更加高效。在实际项目中,可以根据需要调整日志的格式和内容,确保日志既可以被机器解析,又能让人类快速定位和理解。