Java 21和Spring Boot 3升级笔记(五)日志指标与可观测性

发表于 2024-11-15 21:39 1140 字 6 min read

Spring AI学习笔记(四)工具调用和MCPSpring AI学习笔记(三)RAG从文档入库到回答Spring AI学习笔记(二)ChatClient从怎么调到怎么封装Spring AI学习笔记(一)它到底解决什么问题java新版本-java25学习笔记(四)用JFR和GC日志做一次体检java新版本-java25学习笔记(三)虚拟线程要和资源边界一起看java新版本-java25学习笔记(二)运行时基线先统一java新版本-java25学习笔记(一)LTS版本对比和学习路线主流AI Agent能力对比与工程选型我用Kiro做了个自己的工具站盘一盘虚拟线程我用Trae做了个AstrBot的AI角色扮演插件Python初学笔记(六)常用标准库先学这几个Python初学笔记(五)读写文件和处理异常Python初学笔记(四)函数让代码开始有结构Python初学笔记(三)条件、循环和推导式Python初学笔记(二)变量和基础类型比想象中重要Python初学笔记(一)先把环境和运行方式弄明白主流AI大模型能力对比Java 21和Spring Boot 3升级笔记(五)日志指标与可观测性Java 21和Spring Boot 3升级笔记(四)数据访问层适配Java 21和Spring Boot 3升级笔记(三)虚拟线程使用边界Java 21和Spring Boot 3升级笔记(二)Jakarta迁移要点Java 21和Spring Boot 3升级笔记(一)工程基线整理魔法値をどうやって我慢する?JPAのSpecification大改造!处理生僻字乱码:JPA框架对于Oracle的NVarchar2,NChar,NClob类型支持Redis Stream能不能当轻量消息队列用RocketMQ 5学习笔记:普通消息之外要看什么事件流不是换个消息队列这么简单Kubernetes学习笔记04:发布、排障和观测Kubernetes学习笔记03:配置、密钥和存储Kubernetes学习笔记02:Deployment、Service和IngressKubernetes学习笔记01:Pod和控制器mysql索引原理02--存储引擎索引的实现mysql索引原理01--索引的数据结构
この投稿は「日本語」では表示できません。元の投稿を表示しています。
  升级 Java 21 和 Spring Boot 3 后,我觉得还有一件事很值得顺手做:把可观测性补起来。   可观测性这个词听起来有点大,但落到普通 Java 项目里,最基础的就是日志、指标和链路信息。系统出问题时,能不能知道哪个接口慢了,哪个 SQL 卡了,哪个外部服务失败了,这些比“用了新版本”更重要。   Spring...

前言

  升级 Java 21 和 Spring Boot 3 后,我觉得还有一件事很值得顺手做:把可观测性补起来。

  可观测性这个词听起来有点大,但落到普通 Java 项目里,最基础的就是日志、指标和链路信息。系统出问题时,能不能知道哪个接口慢了,哪个 SQL 卡了,哪个外部服务失败了,这些比“用了新版本”更重要。

  Spring Boot 3 生态里,Micrometer、Actuator、OpenTelemetry 这些都比较成熟。即使暂时不上完整链路追踪,也应该先把基础信息打好。

日志先统一格式

  很多项目日志最大的问题不是没有日志,而是日志格式乱。

有的地方打印中文描述,有的地方打印对象,有的地方只打印“执行失败”,没有请求 ID,也没有业务主键。排查问题时只能靠猜。

我更喜欢在日志里至少保留这些信息:

1.traceId。 2.接口路径。 3.业务主键。 4.异常类型。 5.耗时。

比如:

log.info("create order success, orderNo={}, cost={}ms", orderNo, cost);

不要写成:

log.info("创建订单成功");

后者人能看懂,但机器和排查都不好用。

traceId 要贯穿请求

  一个请求从网关到后端服务,再到数据库和外部接口,如果没有统一的 traceId,日志很难串起来。

哪怕暂时没有接完整链路追踪,也可以先在入口过滤器里生成 traceId,放到 MDC 里。

MDC.put("traceId", traceId);

日志格式里再带上traceId。这样用户反馈一个问题时,只要能找到一次请求日志,就能往下查整条链路。

如果后面接 OpenTelemetry,也是在这个基础上继续扩展,而不是从零开始。

Actuator 不要裸开

  Spring Boot Actuator 很方便,可以提供健康检查、指标、环境信息等端点。

但 Actuator 不能随便裸开到公网。尤其是envbeansconfigprops这类端点,信息量很大,暴露出去有风险。

我一般会先只开放必要端点:

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus

生产环境再配合网络隔离或权限控制。监控要有,但不能为了方便把内部信息全放出去。

指标比日志更适合看趋势

  日志适合查单次问题,指标适合看趋势。

比如接口平均耗时、P95 耗时、错误率、数据库连接池使用率、JVM 内存、GC 次数,这些都不适合靠翻日志看。

Spring Boot 里接 Micrometer 后,很多指标已经有默认采集。比如 JVM、HTTP 请求、数据源连接池。

如果业务上有关键动作,也可以自己打指标:

Counter.builder("order.create.count")
        .description("order create count")
        .register(meterRegistry)
        .increment();

业务指标不要一开始打太多,先挑真正会被看、会用于告警的。指标太多没人看,也是一种噪音。

慢接口要能定位到原因

  接口慢的时候,最好能拆出时间花在哪里。

是 Controller 入参处理慢?业务逻辑慢?数据库慢?还是外部接口慢?

简单做法是在关键步骤打耗时日志:

long start = System.currentTimeMillis();
Order order = orderRepository.findById(orderId);
log.info("query order cost={}ms, orderId={}", System.currentTimeMillis() - start, orderId);

正式项目可以用 AOP 或拦截器统一做,但不要过度封装到看不懂。先保证关键路径有信息。

升级后尤其要关注耗时变化。比如开启虚拟线程后,应用线程不是瓶颈了,但数据库连接等待变长了。如果没有连接池指标,就容易误判。

异常日志不要丢堆栈

  有些代码会这样写:

log.error("调用失败:{}", e.getMessage());

这样日志里没有堆栈,排查会很难。更好的写法是:

log.error("call pay service failed, orderNo={}", orderNo, e);

异常消息给人看,堆栈给开发定位。两者都要有。

同时也不要所有异常都打 error。参数校验失败、用户没权限这类可预期异常,可以按业务日志处理。真正的系统异常、外部依赖失败、数据不一致,才需要重点告警。

小结

  Java 21 和 Spring Boot 3 带来了新的技术基线,但系统能不能长期稳定运行,还是要看可观测性。

  我的建议是先把日志格式、traceId、Actuator、基础指标和异常堆栈做好。不要一开始追求很复杂的平台,先保证问题来了能查、性能变了能看、异常多了能发现。

気に入ったならばコメントを残してくださいね~

© 2019 - 2026 VincentHo @VincentHo
Powered by theme astro-koharu · Inspired by Shoka