Arthas实践--使用redefine排查应用奇怪的日志来源

栏目: Java · 发布时间: 6年前

内容简介:随着应用越来越复杂,依赖越来越多,日志系统越来越混乱,有时会出现一些奇怪的日志,比如:那么怎样排查这些奇怪的日志从哪里打印出来的呢?因为搞不清楚是什么logger打印出来的,所以想定位就比较头疼。下面介绍用Alibaba开源的应用诊断利器Arthas的redefine命令快速定位奇怪日志来源。

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

[] [] [] No credential found

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

下面介绍用Alibaba开源的应用诊断利器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."<init>":(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.class
redefine success, size: 1

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

[] [] [] No credential found
java.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的功能过于强大,所以请小心使用:)

Arthas实践系列


以上所述就是小编给大家介绍的《Arthas实践--使用redefine排查应用奇怪的日志来源》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

电脑报(上下册)

电脑报(上下册)

电脑报社 / 西南师范大学出版社 / 2006-12-01 / 45.00元

全套上、下两册,浓缩2006年电脑报精华文章。附录包含70余篇简明IT应用指南,覆盖软件、硬盘、数码、网络四大领域。配赠权威实用的2006-2007中国计算机年鉴DVD光盘,近1.4GB海量信息与资源超值奉献。8大正版超值软件,涵盖系统维护、系统安全、办公应用、多媒体娱乐等四大领域。微软、腾讯、友立等知名厂商,新年献礼。提供2006-2007全系列硬件、数码产品资讯,兼具知识性与资料性。官方网站全......一起来看看 《电脑报(上下册)》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具