记一次用Arthas线上debug实战

问题描述

在线上运行的项目中遇到bug。排查中怀疑是配置文件中的bean读取没有成功。一般个人作法是加一行日志,再从新上线代码。好比这样: log.info("WxDomainProperties:{}",wxDomainProperties);git

来看一下这个对象的属性究竟是怎么样的。github

不过这显然是一种比较低效的方式。下面介绍一种用阿里开源的arthas来实现线上debug的方式。web

先看下相关的代码

被怀疑出现问题的bean就是下面这个bean,主要是用来配置域名信息。经过配置文件配置的值。在不一样环境中,好比dev,local,online会有不一样值。docker

/**
 * 微信第三方平台域名配置
 *
 * @author yanghaolei
 * @date 2019/08/07 下午4:04
 */
@Data
@Component
@ConfigurationProperties(prefix = WxDomainProperties.PREFIX)
public class WxDomainProperties {

    public static final String PREFIX = "wx.domain";

    /**
     * 请求域名
     */
    private List<String> requestDomainList = Lists.newArrayList();

    /**
     * WebSocket域名
     */
    private List<String> wsRequestDomainList = Lists.newArrayList();

    /**
     * 上传域名
     */
    private List<String> uploadDomainList = Lists.newArrayList();

    /**
     * 下载域名
     */
    private List<String> downloadDomainList = Lists.newArrayList();

    /**
     * 业务域名
     */
    private List<String> webviewDomainList = Lists.newArrayList();
}

复制代码

接下来咱们注入这个bean到业务代码中。bash

@Slf4j
@AllArgsConstructor
@Service
public class MaDomainService {
    private final WxService wxService;
    private final WxDomainProperties wxDomainProperties;
复制代码

在方法setDoamin中,bean储存的值会在默认状况下被自动载入。而我遇到的bug就是发如今默认状况下,载入的值都是null。因此我怀疑这个配置读取的值有问题。微信

public WxOpenMaDomainResult setDomain(MaDomainSetDTO maDomainSetDTO) {
        JSONObject requestJson = new JSONObject();
        Integer status = maDomainSetDTO.getStatus();
        String appId = maDomainSetDTO.getAppId();

        // 1 启用默认配置 --> 强制覆盖成默认列表[初始化操做]
        if (StatusEnum.TRUE.getValue().equals(status)) {
            requestJson.put("action", SET_ACTION);
            requestJson.put("requestdomain", JSONArray.parse(JSON.toJSONString(wxDomainProperties.getRequestDomainList())));
            requestJson.put("wsrequestdomain", JSONArray.parseArray(JSON.toJSONString(wxDomainProperties.getWsRequestDomainList())));
            requestJson.put("uploaddomain", JSONArray.parseArray(JSON.toJSONString(wxDomainProperties.getUploadDomainList())));
            requestJson.put("downloaddomain", JSONArray.parseArray(JSON.toJSONString(wxDomainProperties.getDownloadDomainList())));
        }
        // 2 未启用默认配置 --> 能够add/delete/get[不容许自定义set]
        else if (StatusEnum.FALSE.getValue().equals(status)) {
            //不容许自定义覆盖
            if (SET_ACTION.equals(maDomainSetDTO.getAction())) {
                return new WxOpenMaDomainResult();
            }
            requestJson.put("requestdomain", getJsonArray(maDomainSetDTO.getRequestDomainList()));
            requestJson.put("wsrequestdomain", getJsonArray(maDomainSetDTO.getWsRequestDomainList()));
            requestJson.put("uploaddomain", getJsonArray(maDomainSetDTO.getUploadDomainList()));
            requestJson.put("downloaddomain", getJsonArray(maDomainSetDTO.getDownloadDomainList()));
        } else {
            return new WxOpenMaDomainResult();
        }

        try {
            String response = wxService.getMaService(appId).post(API_MODIFY_DOMAIN, requestJson.toJSONString());
            return JSON.parseObject(response, WxOpenMaDomainResult.class);
        } catch (Exception e) {
            log.error("Error message:{},Error stackTrace:{}", e.getMessage(), e.getStackTrace());
            return new WxOpenMaDomainResult();
        }
    }

复制代码

为了验证个人怀疑没有问题,固然是须要debug去检查下这个值。可是这个是线上代码,像开始说的经过加日志重启检查值是比较麻烦的事情。因此想到了用arthas来作线上debug。app

Arthas 实战

网上大部分资料对于arthas的介绍都停留于怎么安装和看一些控制台的信息。这里给出官网,Arthas 入门。我主要会讲我经过arthas验证个人怀疑和最后找到缘由的过程。dom

我这里用到的命令是watch和trace。jvm

watch命令执行数据观测,让咱们能方便的观察到指定方法的调用状况。watch的格式是: watch + 类名表达式匹配 + 方法名 + 表达式 + 条件表达式。 我这里是想观察方法setDomain在调用过程当中wxDomainProperties的值是否成功由配置文件读取。因此个人表达式是:watch + 类名[com.bjyt.bange.module.wx.middleware.MaDomainService] + 方法名[setDomain] + 表达式['target.wxDomainProperties' ]。这里target表示当前对象。条件表达式每每用来指定观察点和观察时间,这里不须要因此就没填。能够看到执行的结果:post

能够看到个人怀疑是错的,这个bean是有值的。因此这也是为何加日志效率低的缘由,会浪费不少时间去验证一个错的怀疑。

接下来我用到了trace命令,但愿经过跟踪方法内部究竟是怎么跑的。trace命令能够跟踪方法内部调用路径,并输出方法路径上的每一个节点上耗时。它与stack不同的地方是stack输出的是当前方法的被调用路径。trace的格式一样是trace + 类名 + 方法名 + 表达式。下面是执行的结果:

这里能够明显看到倒数第二行的位置抛出了异常。通过分析发现是本身的代码写错了。。。最终根据arthas的结果咱们完成了一次线上debug。

最后: 关于k8s或者docker中使用arthas

arthas是须要获取当前机器运行的jvm进程才能够工做的。在实际生产环境中,咱们线上的机器应该都是部署在k8s或者docker中的。也就是说这些线上的机器一样须要安装arthas。阿里的官方指导中也特别提到了这一点,关于在容器中部署arthas。

实际上,我认为比较好的方式是开发人员在本身的本地安装arthas。而后经过arthas的webConsole链接到docker上的arthas。而后经过控制台进行远程线上的debug。关于这一点也在官方的user-case中找到了印证。记录如何使用arthas进行远程访问 #442。这样就能搭建一个更高效率的开发模式。并且还能大大减小代码中的诸如log.info这样的日志代码量。再考虑到arthas的功能远远不止于此,应该说仍是值得去考虑的。

相关文章
相关标签/搜索