想象一下这样的场景,如果生产上运行的应用没有输出关键日志,而我们又想在不重启应用的情况下,输出我们想要的日志,比如打印某个方法的执行耗时,那么可以怎么处理呢?

也许你会说,打印耗时还不简单,通过arthas的trace命令就可以看到,这个确实可以,例如下面的命令。

trace com.wangji92.arthas.plugin.demo.controller.CommonController traceE  -n 5 --skipJDKMethod false 

image-1703975818082

但是如果我们想改变方法的返回值,那么用trace命令就做不到了,另外,我们想把方法的执行耗时输出到日志一段时间,方便分析,trace命令同样做不到。那么arthas怎么做热更新的呢?需要用到以下几个步骤。

【步骤一】用jad反编译,并输出源码到本地

jad --source-only com.wangji92.arthas.plugin.demo.service.impl.ArthasTestServiceImpl > /root/arthas/ArthasTestServiceImpl.java

然后编辑 /root/arthas/ArthasTestServiceImpl.java,修改返回的返回值,增加记录执行耗时的日志输出。


           public String doTraceE(String name) {
               try {
                   long start = System.currentTimeMillis();
/*19*/             Thread.sleep(1000L);
/*21*/             if (StringUtils.isEmpty((Object)name)) {
                       name = System.currentTimeMillis() + "";
                   }
                   long end = System.currentTimeMillis();

                   log.info("doTraceE方法执行耗时:{}", end - start);
                   return Thread.currentThread().getName() + " - HELLO ARTHAS";
               }
               catch (InterruptedException e) {
/*27*/             log.error("InterruptedException", (Throwable)e);
/*29*/             return "";
               }
           }


【步骤二】用mc命令进行编译

在用mc编译之前,需要用sc命令查看com.wangji92.arthas.plugin.demo.service.impl.ArthasTestServiceImpl这个类用的是哪个类加载器,因为编译的时候需要用到,具体命令如下:

sc com.wangji92.arthas.plugin.demo.service.impl.ArthasTestServiceImpl

image-1703975852494

上面截图中的classLoaderHash对应的值31cefde0就是类加载器对应的hash码。
通过mc命令进行编译,命令如下:

mc -c 31cefde0 /root/arthas/ArthasTestServiceImpl.java  -d /root/arthas/

image-1703975885115

没有任何报错的话说明编译成功。

这里说明一下为什么要指定类加载器31cefde0,因为ArthasTestServiceImpl这个类中用到了一些自定义的类,比如实现了ArthasTestService接口,如果用默认的类加载器的话,则会找不到该接口类的错误。

【步骤三】用redefine命令进行热加载

redefine -c 31cefde0 /root/arthas/com/wangji92/arthas/plugin/demo/service/impl/ArthasTestServiceImpl.class

image-1703975926698

没有任何报错的话说明编译成功。

【步骤四】测试效果

image-1703975942348

需要注意的是:
① 不允许新增加/删除 field/method
② 正在跑的函数,没有退出不能生效,如果调用ArthasTestServiceImpl的入口:com.wangji92.arthas.plugin.demo.controller.CommonController#traceE,如果你在traceE方法内加入监控执行耗时的日志输出的话,则不会生效。

打赏
支付宝 微信
上一篇 下一篇