领先一步
VMware 提供培训和认证,以加速您的进步。
了解更多日志记录是应用程序故障排除中长期存在的一部分,也是可观察性的三大支柱之一(其他两个是指标和跟踪)。没有人喜欢在生产环境中盲目操作,当发生事故时,开发人员很乐意拥有日志文件。日志通常以人类可读的格式写入。
结构化日志记录是一种技术,其中日志输出以定义明确、通常是机器可读的格式写入。此格式可以馈送到日志管理系统,并启用强大的搜索和分析功能。结构化日志记录最常用的格式之一是JSON。
Spring Boot 3.4 原生支持结构化日志记录。它支持Elastic Common Schema (ECS) 和 Logstash 格式,但也支持使用您自己的格式进行扩展。
让我们直接开始,看看它是如何工作的!
在start.spring.io上创建一个新项目。您不需要添加任何依赖项,但请确保至少选择 Spring Boot 3.4.0-M2。
要在控制台上启用结构化日志记录,请将此添加到您的application.properties
中
logging.structured.format.console=ecs
这将指示 Spring Boot 以 Elastic Common Schema (ECS) 格式记录日志。
现在启动应用程序,您将看到日志以 JSON 格式显示
{"@timestamp":"2024-07-30T08:41:10.561295200Z","log.level":"INFO","process.pid":67455,"process.thread.name":"main","service.name":"structured-logging-demo","log.logger":"com.example.structured_logging_demo.StructuredLoggingDemoApplication","message":"Started StructuredLoggingDemoApplication in 0.329 seconds (process running for 0.486)","ecs.version":"8.11"}
很酷,对吧?现在让我们深入探讨更高级的主题。
您还可以将结构化日志记录启用到文件。例如,这可以用于在控制台上打印人类可读的日志,并将结构化日志写入文件以进行机器摄取。
要启用该功能,请将此添加到您的application.properties
中,并确保删除logging.structured.format.console=ecs
设置
logging.structured.format.file=ecs
logging.file.name=log.json
现在启动您的应用程序,您将看到控制台上有人类可读的日志,并且文件log.json
包含机器可读的 JSON 内容。
结构化日志记录的一个强大功能是,开发人员可以以结构化的方式向日志事件添加信息。例如,您可以向每个日志事件添加用户 ID,然后稍后根据该 ID 进行筛选以查看此特定用户做了什么。
Elastic Common Schema 和 Logstash 都包含Mapped Diagnostic Context 的内容在 JSON 中。为了实际看到这一点,让我们创建我们自己的日志消息
@Component
class MyLogger implements CommandLineRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(MyLogger.class);
@Override
public void run(String... args) {
MDC.put("userId", "1");
LOGGER.info("Hello structured logging!");
MDC.remove("userId");
}
}
在记录日志消息之前,此代码还在 MDC 中设置用户 ID。Spring Boot 会自动将用户 ID 包含在 JSON 中
{ ... ,"message":"Hello structured logging!","userId":"1" ... }
您还可以使用流畅的日志记录 API 添加附加字段,而无需依赖 MDC
@Component
class MyLogger implements CommandLineRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(MyLogger.class);
@Override
public void run(String... args) {
LOGGER.atInfo().setMessage("Hello structured logging!").addKeyValue("userId", "1").log();
}
}
Elastic Common Schema 定义了许多字段名称,Spring Boot 内置支持服务名称、服务版本、服务环境和节点名称。要为这些字段设置值,您可以在您的application.properties
中使用以下内容
logging.structured.ecs.service.name=MyService
logging.structured.ecs.service.version=1
logging.structured.ecs.service.environment=Production
logging.structured.ecs.service.node-name=Primary
查看 JSON 输出时,现在有service.name
、service.version
、service.environment
和service.node.name
字段。有了这些,您现在可以在您的日志系统中根据节点名称、服务版本等进行筛选。
如上所述,Spring Boot 原生支持 Elastic Common Schema 和 Logstash 格式。要添加您自己的格式,您必须执行以下步骤
StructuredLogFormatter
接口的自定义实现application.properties
中引用您的自定义实现首先,让我们创建我们自己的自定义实现
class MyStructuredLoggingFormatter implements StructuredLogFormatter<ILoggingEvent> {
@Override
public String format(ILoggingEvent event) {
return "time=" + event.getTimeStamp() + " level=" + event.getLevel() + " message=" + event.getMessage() + "\n";
}
}
如您所见,结构化日志记录支持不限于 JSON,您可以返回任何您想要的String
。在此示例中,我们选择使用key=value
对。
现在我们需要让 Spring Boot 了解我们的自定义实现。为此,请将此添加到application.properties
中
logging.structured.format.console=com.example.structured_logging_demo.MyStructuredLoggingFormatter
是时候启动应用程序并欣赏日志输出了!
time=1722330118045 level=INFO message=Hello structured logging!
哇,看看这个!多么漂亮的日志输出!
如果您想编写 JSON,Spring Boot 3.4 中有一个方便的新JsonWriter
,您可以使用它
class MyStructuredLoggingFormatter implements StructuredLogFormatter<ILoggingEvent> {
private final JsonWriter<ILoggingEvent> writer = JsonWriter.<ILoggingEvent>of((members) -> {
members.add("time", (event) -> event.getInstant());
members.add("level", (event) -> event.getLevel());
members.add("thread", (event) -> event.getThreadName());
members.add("message", (event) -> event.getFormattedMessage());
members.add("application").usingMembers((application) -> {
application.add("name", "StructuredLoggingDemo");
application.add("version", "1.0.0-SNAPSHOT");
});
members.add("node").usingMembers((node) -> {
node.add("hostname", "node-1");
node.add("ip", "10.0.0.7");
});
}).withNewLineAtEnd();
@Override
public String format(ILoggingEvent event) {
return this.writer.writeToString(event);
}
}
当然,您也可以使用任何其他 JSON 库(例如 Jackson)来创建 JSON,您不必使用JsonWriter
。
生成的日志消息如下所示
{"time":"2024-07-30T09:14:49.377308361Z","level":"INFO","thread":"main","message":"Hello structured logging!","application":{"name":"StructuredLoggingDemo","version":"1.0.0-SNAPSHOT"},"node":{"hostname":"node-1","ip":"10.0.0.7"}}
我们希望您喜欢 Spring Boot 3.4 中的这个新功能!文档 也已更新为结构化日志记录。
请告诉我们您的想法,如果您发现任何问题,我们的问题跟踪器始终是开放的!