博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Alibaba Java诊断利器Arthas实践--使用redefine排查应用奇怪的日志来源
阅读量:6940 次
发布时间:2019-06-27

本文共 3235 字,大约阅读时间需要 10 分钟。

hot3.png

背景

随着应用越来越复杂,依赖越来越多,日志系统越来越混乱,有时会出现一些奇怪的日志,比如:

[] [] [] No credential found

那么怎样排查这些奇怪的日志从哪里打印出来的呢?因为搞不清楚是什么logger打印出来的,所以想定位就比较头疼。

下面介绍用arthas的redefine命令快速定位奇怪日志来源。

  • Alibaba Java 诊断利器Arthas:
  • redefine命令:

修改StringBuilder

首先在java代码里,字符串拼接基本都是通过StringBuilder来实现的。比如下面的代码:

    public static String hello(String world) {        return "hello " + world;    }

实际上生成的字节码也是用StringBuilder来拼接的:

  public static java.lang.String hello(java.lang.String);    descriptor: (Ljava/lang/String;)Ljava/lang/String;    flags: ACC_PUBLIC, ACC_STATIC    Code:      stack=3, locals=1, args_size=1         0: new           #22                 // class java/lang/StringBuilder         3: dup         4: ldc           #24                 // String hello         6: invokespecial #26                 // Method java/lang/StringBuilder."
":(Ljava/lang/String;)V         9: aload_0        10: invokevirtual #29                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;        13: invokevirtual #33                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;        16: areturn

在java的logger系统里,输出日志时通常也是StringBuilder来实现的,最终会调用StringBuilder.toString(),那么我们可以修改StringBuilder的代码来检测到日志来源。

StringBuilder.toString() 的原生实现是:

    @Override    public String toString() {        // Create a copy, don't share the array        return new String(value, 0, count);    }

修改为:

    @Override    public String toString() {        // Create a copy, don't share the array        String result = new String(value, 0, count);        if(result.contains("No credential found")) {            System.err.println(result);            new Throwable().printStackTrace();        }        return result;    }

增加的逻辑是:当String里包含No credential found时打印出当前栈,这样子就可以定位日志输出来源了。

编绎修改过的StringBuilder

其实很简单,在IDE里把StringBuilder的代码复制一份,然后贴到任意一个工程里,然后编绎即可。

也可以直接用javac来编绎:

javac StringBuilder.java

启动应用,使用Arthas redefine修改过的StringBuilder

启动应用后,在奇怪日志输出之前,先使用arthas attach应用,再redefine StringBuilder:

$ redefine -p /tmp/StringBuilder.classredefine success, size: 1

当执行到输出[] [] [] No credential found的logger代码时,会打印当前栈。实际运行结果是:

[] [] [] No credential foundjava.lang.Throwable    at java.lang.StringBuilder.toString(StringBuilder.java:410)    at com.taobao.middleware.logger.util.MessageUtil.getMessage(MessageUtil.java:26)    at com.taobao.middleware.logger.util.MessageUtil.getMessage(MessageUtil.java:15)    at com.taobao.middleware.logger.slf4j.Slf4jLogger.info(Slf4jLogger.java:77)    at com.taobao.spas.sdk.common.log.SpasLogger.info(SpasLogger.java:18)    at com.taobao.spas.sdk.client.identity.CredentialWatcher.loadCredential(CredentialWatcher.java:128)    at com.taobao.spas.sdk.client.identity.CredentialWatcher.access$200(CredentialWatcher.java:18)    at com.taobao.spas.sdk.client.identity.CredentialWatcher$1.run(CredentialWatcher.java:58)    at java.util.TimerThread.mainLoop(Timer.java:555)    at java.util.TimerThread.run(Timer.java:505)

可以看到是spas.sdk打印出了[] [] [] No credential found的日志。

总结

  • logger最终会用StringBuilder来输出
  • 修改StringBuilder来定位输出特定日志的地方
  • 使用Arthas redefine命令来加载修改过的StringBuilder
  • redefine命令实际上实现了任意代码线上debug的功能,可以随意本地修改代码重新编绎,然后线上redefine加载
  • redefine的功能过于强大,所以请小心使用:)

转载于:https://my.oschina.net/hengyunabc/blog/2251535

你可能感兴趣的文章
[Python] Hermite 插值
查看>>
带头节点的单链表的插入操作优化
查看>>
winSockets编程(七)WSAAsyncSelect模式
查看>>
Huffman Codes
查看>>
求一棵二叉树的镜像
查看>>
Principal Component Analysis(PCA) algorithm summary
查看>>
【安装Ubuntu 遇到问题】 the system is running in low-graphics mode 最新办法解决
查看>>
达拉草201771010105《面向对象程序设计(java)》第十八周学习总结
查看>>
Mysql中文输入出现1366错误的解决办法
查看>>
Ant调用Java中文显示乱码
查看>>
database工具
查看>>
[转] JavaScript 运行机制详解:再谈Event Loop
查看>>
我的转正申请
查看>>
【leetcode】509. Fibonacci Number
查看>>
day10--进程
查看>>
结构训练
查看>>
查询数据库保存成CSV格式
查看>>
enumerate
查看>>
PHP三元运算符 isset的理解
查看>>
dede织梦:文章内容页调用
查看>>