From 876c152458ceb17ad76d41c0cce4af76d54c90f7 Mon Sep 17 00:00:00 2001 From: chen Date: Thu, 6 Sep 2018 15:40:02 +0800 Subject: [PATCH] [WEEX-606][Android]fix monitor data (#1497) * [Android] writescreen check stage limimt * [Android] add writescreen swtich * [Android] monitor download failed * [Android] when download success,report download stage --- .../java/com/taobao/weex/WXSDKInstance.java | 11 +- .../com/taobao/weex/common/WXErrorCode.java | 18 +-- .../taobao/weex/common/WXJSExceptionInfo.java | 15 +-- .../weex/performance/WXInstanceApm.java | 10 +- .../WXInstanceExceptionRecord.java | 106 +++++++++--------- .../taobao/weex/utils/WXExceptionUtils.java | 25 ++++- 6 files changed, 103 insertions(+), 82 deletions(-) diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java index 6e4c35b07d..33e85b3c99 100644 --- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java +++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java @@ -1267,6 +1267,7 @@ public void onChangeElement(WXComponent component, boolean isOutOfScreen) { } public void onRenderError(final String errCode, final String msg) { + getExceptionRecorder().recordReportErrorMsg("["+errCode+",onRenderError,"+msg+"]"); if (mRenderListener != null && mContext != null) { runOnUiThread(new Runnable() { @@ -1281,6 +1282,7 @@ public void run() { } public void onJSException(final String errCode, final String function, final String exception) { + getExceptionRecorder().recordReportErrorMsg("["+errCode+","+function+","+exception+"]"); if (mRenderListener != null && mContext != null) { runOnUiThread(new Runnable() { @@ -1846,7 +1848,6 @@ public void onHttpResponseProgress(int loadedLength) { @Override public void onHttpFinish(WXResponse response) { - mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_END); if (this.instance != null && this.instance.getWXStatisticsListener() != null) { @@ -1927,6 +1928,7 @@ public void onHttpFinish(WXResponse response) { WXLogUtils.renderPerformanceLog("networkTime", mWXPerformance.networkTime); String wxErrorCode = WXInstanceApm.VALUE_ERROR_CODE_DEFAULT; if (response!=null && response.originalData!=null && TextUtils.equals("200", response.statusCode)) { + mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_END); String template = new String(response.originalData); render(pageName, template, options, jsonInitData, flag); @@ -1951,6 +1953,7 @@ public void onHttpFinish(WXResponse response) { ); } else { + getExceptionRecorder().isDownLoadBundleFailed = true; wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED.getErrorCode(); onRenderError(wxErrorCode, response.errorMsg); @@ -1974,10 +1977,10 @@ private boolean isNet(String requestType){ public String getTemplateInfo() { String template = getTemplate(); if(template == null){ - return " template md5 null " + JSONObject.toJSONString(responseHeaders); + return " template md5 null ,httpHeader:" + JSONObject.toJSONString(responseHeaders); } if(TextUtils.isEmpty(template)){ - return " template md5 length 0 " + JSONObject.toJSONString(responseHeaders); + return " template md5 length 0 ,httpHeader" + JSONObject.toJSONString(responseHeaders); } try { byte[] bts = template.getBytes("UTF-8"); @@ -1992,7 +1995,7 @@ public String getTemplateInfo() { return " template md5 " + sourceMD5 + " length " + bts.length + " base64 md5 " + sourceBase64MD5 + " response header " + JSONObject.toJSONString(responseHeaders); - } catch (UnsupportedEncodingException e) { + } catch (Exception e) { return "template md5 getBytes error"; } diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java b/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java index cf2d49ac26..ec260e5be9 100644 --- a/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java +++ b/android/sdk/src/main/java/com/taobao/weex/common/WXErrorCode.java @@ -196,8 +196,8 @@ public enum WXErrorCode { /** * WX Key Exception Commit Bundle Js Download */ - WX_KEY_EXCEPTION_JS_DOWNLOAD("-9200", "[WX_KEY_EXCEPTION_JS_DOWNLOAD]|",ErrorType.NATIVE_ERROR,ErrorGroup.NET), - WX_KEY_EXCEPTION_JS_DOWNLOAD_FAILED("-9201", "[WX_KEY_EXCEPTION_JS_DOWNLOAD_FAILED] | details",ErrorType.NATIVE_ERROR,ErrorGroup.NET), + WX_KEY_EXCEPTION_JS_DOWNLOAD("-9200", "[WX_KEY_EXCEPTION_JS_DOWNLOAD]|",ErrorType.DOWN_LOAD_ERROR,ErrorGroup.NATIVE), + WX_KEY_EXCEPTION_JS_DOWNLOAD_FAILED("-9201", "[WX_KEY_EXCEPTION_JS_DOWNLOAD_FAILED] | details",ErrorType.DOWN_LOAD_ERROR,ErrorGroup.NATIVE), /** * WX Key Exception Commit RT DomAction Excute @@ -245,7 +245,7 @@ public enum WXErrorCode { /** * degrade code. */ - WX_DEGRAD_ERR("-1000", "degradeToH5|Weex DegradPassivity \n",ErrorType.DEGRAD_ERROR,ErrorGroup.JS), + WX_DEGRAD_ERR("-1000", "degradeToH5|Weex DegradPassivity ->",ErrorType.DEGRAD_ERROR,ErrorGroup.JS), /** * degrade for instance create failed, once this case occured,detail js stack and other specific @@ -257,20 +257,20 @@ public enum WXErrorCode { * degrade for network failed download js bundle.once this case occured,network requist response header * and statuscode need track into errmsg. */ - WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED("-1002", "|wx_network_error|js bundle download failed",ErrorType.DEGRAD_ERROR,ErrorGroup.NET), + WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED("-1002", "|wx_network_error|js bundle download failed",ErrorType.DOWN_LOAD_ERROR,ErrorGroup.NATIVE), /** * degrade for network failed for bundlejs is unbroken , once this case occured,network requist response header * and statuscode need track into errmsg. */ - WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED("-1003", "degradeToH5|wx_network_error|js bundle content-length check failed",ErrorType.DEGRAD_ERROR,ErrorGroup.NET), + WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED("-1003", "degradeToH5|wx_network_error|js bundle content-length check failed",ErrorType.DEGRAD_ERROR,ErrorGroup.NATIVE), /** * degrade for Response header Content-Type is null or not "application/javascript". * once this case occured,network requist response header and statuscode need track into errmsg. */ WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR("-1004", "degradeToH5|wx_user_intercept_error |Content-Type is not application/javascript, " + - "Weex render template must be javascript, please check your request!",ErrorType.DEGRAD_ERROR,ErrorGroup.NET), + "Weex render template must be javascript, please check your request!",ErrorType.DEGRAD_ERROR,ErrorGroup.NATIVE), /** * degrade for other reason. such as white screen which block error for some unknown reason. @@ -337,12 +337,12 @@ public enum ErrorType{ JS_ERROR, NATIVE_ERROR, RENDER_ERROR, - DEGRAD_ERROR + DEGRAD_ERROR, + DOWN_LOAD_ERROR } public enum ErrorGroup{ JS, - NATIVE, - NET + NATIVE } } diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXJSExceptionInfo.java b/android/sdk/src/main/java/com/taobao/weex/common/WXJSExceptionInfo.java index 411e72c7c2..105d2240d2 100644 --- a/android/sdk/src/main/java/com/taobao/weex/common/WXJSExceptionInfo.java +++ b/android/sdk/src/main/java/com/taobao/weex/common/WXJSExceptionInfo.java @@ -133,15 +133,10 @@ public String getJsFrameworkVersion() { @Override public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append("WeexSDKVersion:").append(mWeexVersion) - .append(" JSFrameworkVersion:").append(mJsFrameworkVersion) - .append(" instanceId:").append(mInstanceId) - .append(" bundleUrl:").append(mBundleUrl) - .append(" errCode:").append(mErrCode.getErrorCode()) - .append(" function:").append(mFunction) - .append(" exception:").append(mException) - .append(" extParams:").append(mExtParams); - return buffer.toString(); + return new StringBuilder() + .append(" errCode:").append(null == mErrCode?"unSetErrorCode":mErrCode.getErrorCode()) + .append(",function:").append(null == mFunction?"unSetFuncName":mFunction) + .append(",exception:").append(null == mException?"unSetException":mException) + .toString(); } } diff --git a/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java b/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java index 07f03c1df1..b7227eca96 100644 --- a/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java +++ b/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java @@ -107,6 +107,7 @@ public class WXInstanceApm { private Map recordStatsMap; private boolean isFSEnd; private boolean mHasInit = false; + private boolean mEnd = false; private boolean hasRecordFistInteractionView =false; public final Map extInfo; @@ -148,7 +149,7 @@ public void onStageWithTime(String name,long time){ if (null != instance){ instance.getExceptionRecorder().recordStage(name, time); } - if (null == apmInstance) { + if (null == apmInstance || mEnd) { return; } apmInstance.onStage(name, time); @@ -159,7 +160,7 @@ public void onStageWithTime(String name,long time){ * record property */ public void addProperty(String key, Object value) { - if (null == apmInstance) { + if (null == apmInstance || mEnd) { return; } apmInstance.addProperty(key, value); @@ -169,7 +170,7 @@ public void addProperty(String key, Object value) { * record statistic */ public void addStats(String key, double value) { - if (null == apmInstance) { + if (null == apmInstance || mEnd) { return; } apmInstance.addStats(key, value); @@ -234,11 +235,12 @@ public void onDisAppear(){ * end record */ public void onEnd() { - if (null == apmInstance) { + if (null == apmInstance || mEnd) { return; } onStage(KEY_PAGE_STAGES_DESTROY); apmInstance.onEnd(); + mEnd = true; } public void arriveFSRenderTime() { diff --git a/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceExceptionRecord.java b/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceExceptionRecord.java index 626a520f1d..e1fcb736da 100644 --- a/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceExceptionRecord.java +++ b/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceExceptionRecord.java @@ -29,6 +29,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; +import android.text.TextUtils; import com.taobao.weex.common.WXErrorCode; import com.taobao.weex.common.WXErrorCode.ErrorGroup; import com.taobao.weex.common.WXErrorCode.ErrorType; @@ -42,12 +43,14 @@ public class WXInstanceExceptionRecord { public static final String KEY_EXP_STAGE_LIST = "wxStageList"; private final Map mStageMap; - public final List errorList; + public final List errorList; public final String instanceId; public final AtomicBoolean hasAddView; public final AtomicBoolean hasDegrade; private boolean mHasReportScreenEmpty = false; private boolean mBeginRender = false; + public boolean isDownLoadBundleFailed = false; + public static boolean isReportWriteScreen = true; public WXInstanceExceptionRecord(String instanceId) { this.instanceId = instanceId; @@ -70,20 +73,30 @@ public void recordErrorMsg(WXJSExceptionInfo exceptionInfo) { mHasReportScreenEmpty = true; return; } + recordReportErrorMsg(exceptionInfo.toString()); + } + + public void recordReportErrorMsg(String appendStr){ + if (!isReportWriteScreen){ + return; + } //screen has view, or degrade , will not be empty - if (hasAddView.get() || hasDegrade.get()) { + if (TextUtils.isEmpty(appendStr) || hasAddView.get() || hasDegrade.get()) { return; } if (errorList.size() > sErrorMsgSizeLimit) { errorList.remove(0); } - errorList.add(exceptionInfo); + errorList.add(new StringBuilder() + .append("time ").append(System.currentTimeMillis()) + .append(",msg ").append(appendStr).toString() + ); } public void recordStage(String stage, long time) { if (WXInstanceApm.KEY_PAGE_STAGES_RENDER_ORGIGIN.equals(stage) || WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START.equals(stage) - || WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_START.equals(stage) + || WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END.equals(stage) ) { setBeginRender(true); } @@ -96,7 +109,7 @@ public void setBeginRender(boolean isBegin){ public String convertStageToStr() { if (mStageMap.isEmpty()) { - return "emptyStage"; + return "noStageRecord"; } List> list = new ArrayList<>(mStageMap.entrySet()); Collections.sort(list, new Comparator>() { @@ -115,85 +128,74 @@ public int compare(Entry o1, Entry o2) { private String convertExceptionListToString() { if (errorList.isEmpty()) { - return "empty"; + return ""; } StringBuilder builder = new StringBuilder(); - builder.append("======== error stack start (top5) =====\n"); - for (WXJSExceptionInfo info : errorList) { - builder.append("time :").append(info.time).append("\n") - .append("extErrorCode :").append(info.getErrCode().getErrorCode()).append('\n') - .append("extErrorType :").append(info.getErrCode().getErrorType()).append('\n') - .append("extErrorGroup :").append(info.getErrCode().getErrorGroup()).append('\n') - .append("extErrorMsg :").append(info.getErrCode().getErrorMsg()).append('\n') - .append("extErrorExceptionDetail :").append(info.getException()).append('\n') - .append("extErrorStageList :").append( - info.getExtParams().containsKey(KEY_EXP_STAGE_LIST) ? info.getExtParams().get(KEY_EXP_STAGE_LIST) - : "empty" - ).append("\n") - .append("============= next ==============\n"); + int i = 0; + for (String info : errorList) { + builder.append("error_").append(i).append(": ").append(info).append("--->"); } - builder.append("======== error stack end =====\n"); return builder.toString(); } public void checkEmptyScreenAndReport() { - if (!mBeginRender || mHasReportScreenEmpty || hasAddView.get() || hasDegrade.get()) { + if (!isReportWriteScreen || isDownLoadBundleFailed){ return; } - //2s limit of instance stayTime (case in\quit very fast case) - final long DIFF_LIMIT_FROM_RENDER_URL = 2000; - final long DIFF_LIMIT_FROM_RENDER_TEMPLATE = 1000; - - long curTime = WXUtils.getFixUnixTime(); - Long startRequestTime = mStageMap.get(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START); - long useTime; - String useTimeForm; - boolean shouldReportByUseTime; - if (null != startRequestTime) { - useTime = curTime - startRequestTime; - shouldReportByUseTime = useTime >= DIFF_LIMIT_FROM_RENDER_URL; - useTimeForm = WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START; - }else { - Long startRenderTemplateTime = mStageMap.get(WXInstanceApm.KEY_PAGE_STAGES_RENDER_ORGIGIN); - useTime = null != startRenderTemplateTime?curTime - startRenderTemplateTime:curTime; - shouldReportByUseTime = useTime >= DIFF_LIMIT_FROM_RENDER_TEMPLATE; - useTimeForm = WXInstanceApm.KEY_PAGE_STAGES_RENDER_ORGIGIN; + if (!mBeginRender || mHasReportScreenEmpty || hasAddView.get() || hasDegrade.get()) { + return; } - if (!shouldReportByUseTime){ + Long startExecJsTime = mStageMap.get(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END); + if (null == startExecJsTime){ + //too fast to quit + return; + } + long currentTime = WXUtils.getFixUnixTime(); + long jsExecTime = currentTime - startExecJsTime; + //3s limit of instance stayTime (case in\quit very fast case) + if (jsExecTime <= 3000){ return; } - boolean hasJsException = false; - for (WXJSExceptionInfo info : errorList) { - if (info.getErrCode().getErrorGroup() == ErrorGroup.JS) { - hasJsException = true; - break; - } + String errorMsg; + if(errorList.isEmpty()){ + errorMsg = mStageMap.containsKey(WXInstanceApm.KEY_PAGE_STAGES_CREATE_FINISH) + ?"writeScreen :never add view until page destroy(js has execute > 3s)" + :"writeScreen :never add view even js executeTime > 3s"; + }else { + errorMsg = "writeScreen :history exception :"+ convertExceptionListToString(); } + + Map flagMap = new HashMap<>(4); flagMap.put("wxBeginRender",String.valueOf(mBeginRender)); flagMap.put("wxHasAddView",String.valueOf(hasAddView.get())); flagMap.put("wxHasDegrade",String.valueOf(hasDegrade.get())); flagMap.put("wxHasReportScreenEmpty",String.valueOf(mHasReportScreenEmpty)); - flagMap.put("wxUseTime", String.valueOf(useTime)); - flagMap.put("wxUseTimeForm", useTimeForm); + flagMap.put("wxJSExecTime", String.valueOf(jsExecTime)); WXExceptionUtils.commitCriticalExceptionRT( instanceId, - hasJsException ? WXErrorCode.WX_RENDER_ERR_JS_RUNTIME : WXErrorCode.WX_RENDER_ERR_NATIVE_RUNTIME, + WXErrorCode.WX_RENDER_ERR_JS_RUNTIME, "checkEmptyScreenAndReport", - convertExceptionListToString(), + errorMsg, flagMap ); } + public Long getStageTime(String key){ + return mStageMap.get(key); + } + + + @Override public String toString() { return new StringBuilder() .append(super.toString()) - .append("wxStageList :\n").append(convertStageToStr()) - .append("wxErrorList :\n").append(convertExceptionListToString()) + .append("wxStageList :").append(convertStageToStr()) + .append("wxErrorList :").append(convertExceptionListToString()) .toString(); } } diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXExceptionUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXExceptionUtils.java index 62c5be2a5e..fb67f6053e 100644 --- a/android/sdk/src/main/java/com/taobao/weex/utils/WXExceptionUtils.java +++ b/android/sdk/src/main/java/com/taobao/weex/utils/WXExceptionUtils.java @@ -28,10 +28,10 @@ import com.taobao.weex.WXSDKManager; import com.taobao.weex.adapter.IWXJSExceptionAdapter; import com.taobao.weex.common.WXErrorCode; -import com.taobao.weex.common.WXErrorCode.ErrorType; import com.taobao.weex.common.WXJSExceptionInfo; import com.taobao.weex.common.WXPerformance; import com.taobao.weex.performance.WXAnalyzerDataTransfer; +import com.taobao.weex.performance.WXInstanceApm; import com.taobao.weex.performance.WXInstanceExceptionRecord; /** @@ -108,7 +108,21 @@ public static void commitCriticalExceptionWithDefaultUrl( } commitMap.put(WXInstanceExceptionRecord.KEY_EXP_STAGE_LIST,instance.getExceptionRecorder().convertStageToStr()); String bundleTemplate = instance.getTemplate(); - commitMap.put("wxTemplateOfBundle",null == bundleTemplate ?"has recycle by gc":bundleTemplate); + if (null == bundleTemplate){ + bundleTemplate = "has recycle by gc"; + }else { + int length = bundleTemplate.length(); + bundleTemplate = bundleTemplate.substring(0,Math.min(length,300)); + } + commitMap.put("wxTemplateOfBundle",bundleTemplate); + + Long pageStartTime = instance.getExceptionRecorder().getStageTime(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START); + if (null == pageStartTime){ + pageStartTime = instance.getExceptionRecorder().getStageTime(WXInstanceApm.KEY_PAGE_STAGES_RENDER_ORGIGIN); + } + if (null != pageStartTime){ + commitMap.put("wxUseTime", String.valueOf(WXUtils.getFixUnixTime() - pageStartTime)); + } } } else {//instance is null for instance id is null if (commitMap.size() > 0) { @@ -117,12 +131,17 @@ public static void commitCriticalExceptionWithDefaultUrl( } } + String illegalValue = commitMap.get("errorCode"); + if (null != illegalValue && illegalValue.length()>200){ + commitMap.remove("errorCode"); + } + exceptionCommit = new WXJSExceptionInfo(instanceIdCommit, bundleUrlCommit, errCode, function, exceptionMsgCommit, commitMap); if (adapter != null) { adapter.onJSException(exceptionCommit); } - if (null != instance && exceptionCommit.getErrCode().getErrorType() != ErrorType.RENDER_ERROR){ + if (null != instance ){ instance.getExceptionRecorder().recordErrorMsg(exceptionCommit); }