記一次用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的功能遠遠不止於此,應該說仍是值得去考慮的。

相關文章
相關標籤/搜索