首页
学习
活动
专区
圈层
工具
发布

SpringBoot 实现无痕调试注入器,线上问题定位的新利器

在日常开发里,大家应该都遇到过这种情况:线上出问题,日志信息不够,定位特别慢。传统手段不是要加日志重新发版,就是要远程 debug,但这些方式都不太优雅。SpringBoot 项目里可以搞个“无痕调试注入器”,做到随时加观察点、随时撤销,而且不用动核心业务逻辑。

从注解切面开始

先来个轻量级方案:写一个注解@DebugPoint,配合 Spring AOP 就能把入参、出参和耗时打出来,基本上满足大部分排查需求。

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface DebugPoint {

  String value() default "";

}

切面代码如下:

@Aspect

@Component

public class DebugAspect {

  private static final Logger log = LoggerFactory.getLogger(DebugAspect.class);

  @Around("@annotation(debugPoint)")

  public Object around(ProceedingJoinPoint pjp, DebugPoint debugPoint) throws Throwable {

      String method = pjp.getSignature().toShortString();

      log.info("[DEBUG] 方法: {}, 标签: {}, 参数: {}",

              method, debugPoint.value(), Arrays.toString(pjp.getArgs()));

      long start = System.currentTimeMillis();

      Object result = pjp.proceed();

      long cost = System.currentTimeMillis() - start;

      log.info("[DEBUG] 方法: {}, 耗时: {}ms, 返回: {}", method, cost, result);

      return result;

  }

}

在业务方法上加注解:

@Service

public class OrderService {

  @DebugPoint("订单创建流程")

  public String createOrder(String userId, String productId) {

      return "order-" + UUID.randomUUID();

  }

}

启动应用后,调用createOrder就能在日志里看到完整的调试信息,而业务逻辑完全不用改。

再进一步:热插拔 Agent

如果你想做到“不改源码也能打点”,就要上 Java Agent 了。利用 Instrumentation + ByteBuddy,可以在 JVM 里动态修改字节码,实现运行时增强。

DebugAgent.java:

public class DebugAgent {

  public static void premain(String args, Instrumentation inst) {

      new AgentBuilder.Default()

          .type(ElementMatchers.nameContains("OrderService"))

          .transform((builder, type, cl, module) ->

              builder.method(ElementMatchers.any())

                     .intercept(Advice.to(DebugAdvice.class)))

          .installOn(inst);

  }

}

DebugAdvice.java:

public class DebugAdvice {

  @Advice.OnMethodEnter

  public static void onEnter(@Advice.Origin String method,

                             @Advice.AllArguments Object[] args) {

      System.out.println("[Agent-Enter] 方法: " + method + ", 参数: " + Arrays.toString(args));

  }

  @Advice.OnMethodExit

  public static void onExit(@Advice.Origin String method,

                            @Advice.Return Object result) {

      System.out.println("[Agent-Exit] 方法: " + method + ", 返回: " + result);

  }

}

打包成agent.jar后,用 JVM 参数挂上:

-javaagent:/path/to/agent.jar

这时候即使没有@DebugPoint注解,OrderService里的方法也会被增强,日志会自动打印,真正做到“线上临时加点”。

SpringBoot Demo 骨架

一个最小可运行的 Demo 项目目录大概是这样的:

demo-debug/

├── src/main/java/com/example/debug/

│    ├── DebugPoint.java       # 注解

│    ├── DebugAspect.java      # AOP切面

│    ├── OrderService.java     # 业务服务

│    ├── DemoApplication.java  # 启动类

├── agent/

│    ├── DebugAgent.java       # Java Agent入口

│    ├── DebugAdvice.java      # 增强逻辑

启动方式两种:

普通启动:直接跑 SpringBoot 项目,用注解调试。

带 agent 启动:加-javaagent参数,Agent 会自动注入日志增强。

使用场景

线上只想看某个方法的参数和结果,快速定位异常

不想频繁改业务代码、发版

遇到偶发性问题,需要临时开关调试

这种调试注入器就像个“隐形摄像头”,你想看的时候开一下,排完问题再关掉,不影响线上业务。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OwvrGp3TzmIEcP_rDLmL7Ljg0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券