在線上運行的項目中遇到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驗證個人懷疑和最後找到緣由的過程。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。
arthas是須要獲取當前機器運行的jvm進程才能夠工做的。在實際生產環境中,咱們線上的機器應該都是部署在k8s或者docker中的。也就是說這些線上的機器一樣須要安裝arthas。阿里的官方指導中也特別提到了這一點,關於在容器中部署arthas。
實際上,我認爲比較好的方式是開發人員在本身的本地安裝arthas。而後經過arthas的webConsole鏈接到docker上的arthas。而後經過控制檯進行遠程線上的debug。關於這一點也在官方的user-case中找到了印證。記錄如何使用arthas進行遠程訪問 #442。這樣就能搭建一個更高效率的開發模式。並且還能大大減小代碼中的諸如log.info這樣的日誌代碼量。再考慮到arthas的功能遠遠不止於此,應該說仍是值得去考慮的。