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

简介: ## 背景 随着应用越来越复杂,依赖越来越多,日志系统越来越混乱,有时会出现一些奇怪的日志,比如: ``` [] [] [] No credential found ``` 那么怎样排查这些奇怪的日志从哪里打印出来的呢?因为搞不清楚是什么logger打印出来的,所以想定位就比较头疼。 下面介绍用arthas的redefine命令快速定位奇怪日志来源。 * Ar

背景

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

[] [] [] No credential found

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

下面介绍用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实践系列

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
25天前
|
存储 运维 监控
【Flume】flume 日志管理中的应用
【4月更文挑战第4天】【Flume】flume 日志管理中的应用
|
2月前
|
监控 Serverless 数据库
Serverless 应用引擎常见问题之biphon-education-配置了SLS后一直重启如何解决
Serverless 应用引擎(Serverless Application Engine, SAE)是一种完全托管的应用平台,它允许开发者无需管理服务器即可构建和部署应用。以下是Serverless 应用引擎使用过程中的一些常见问题及其答案的汇总:
28 5
|
2月前
|
运维 监控 数据挖掘
应用研发平台EMAS产品常见问题之将阿里后台的日志落到我们后台失败如何解决
应用研发平台EMAS(Enterprise Mobile Application Service)是阿里云提供的一个全栈移动应用开发平台,集成了应用开发、测试、部署、监控和运营服务;本合集旨在总结EMAS产品在应用开发和运维过程中的常见问题及解决方案,助力开发者和企业高效解决技术难题,加速移动应用的上线和稳定运行。
|
3月前
电子书阅读分享《Elasticsearch全观测技术解析与应用(构建日志、指标、APM统一观测平台)》
电子书阅读分享《Elasticsearch全观测技术解析与应用(构建日志、指标、APM统一观测平台)》
235 1
|
7天前
|
监控 JavaScript Java
|
2月前
|
存储 SQL Serverless
Serverless 应用引擎常见问题之应用下的【应用事件】以及企业级特性下的【事件中心】没有日志如何解决
Serverless 应用引擎(Serverless Application Engine, SAE)是一种完全托管的应用平台,它允许开发者无需管理服务器即可构建和部署应用。以下是Serverless 应用引擎使用过程中的一些常见问题及其答案的汇总:
34 0
|
3月前
|
供应链 Java 测试技术
开发Java应用时如何用好Log
开发Java应用时如何用好Log
77 3
|
28天前
|
Java
使用Java代码打印log日志
使用Java代码打印log日志
89 1
|
29天前
|
Linux Shell
Linux手动清理Linux脚本日志定时清理日志和log文件执行表达式
Linux手动清理Linux脚本日志定时清理日志和log文件执行表达式
81 1
|
2月前
|
SQL 关系型数据库 MySQL
MySQL数据库,可以使用二进制日志(binary log)进行时间点恢复
对于MySQL数据库,可以使用二进制日志(binary log)进行时间点恢复。二进制日志是MySQL中记录所有数据库更改操作的日志文件。要进行时间点恢复,您需要执行以下步骤: 1. 确保MySQL配置文件中启用了二进制日志功能。在配置文件(通常是my.cnf或my.ini)中找到以下行,并确保没有被注释掉: Copy code log_bin = /path/to/binary/log/file 2. 在需要进行恢复的时间点之前创建一个数据库备份。这将作为恢复的基准。 3. 找到您要恢复到的时间点的二进制日志文件和位置。可以通过执行以下命令来查看当前的二进制日志文件和位
102 1