blob: 1bf7d7fbd51da4711d91ed5553ebd648c302152a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.taobao.weex.utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.taobao.weex.WXEnvironment;
import com.taobao.weex.WXSDKInstance;
import com.taobao.weex.WXSDKManager;
import com.taobao.weex.adapter.IWXConfigAdapter;
import com.taobao.weex.adapter.IWXJSExceptionAdapter;
import com.taobao.weex.common.WXErrorCode;
import com.taobao.weex.common.WXErrorCode.ErrorGroup;
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.WXStateRecord;
/**
* Created on 2017/10/13.
*/
public class WXExceptionUtils {
private static Set<String> sGlobalExceptionRecord = new CopyOnWriteArraySet<String>();
/**
* degradeUrl for degrade case
*/
public static String degradeUrl = "BundleUrlDefaultDegradeUrl";
private static boolean checkNeedReportCauseRepeat(String instanceId,WXErrorCode errCode,String exception){
if (TextUtils.isEmpty(exception)){
return true;
}
if (null != errCode && errCode.getErrorGroup() != ErrorGroup.JS){
return true;
}
if (TextUtils.isEmpty(instanceId)){
instanceId = "instanceIdNull";
}
String targetException = exception.length() > 200 ?exception.substring(0,200) : exception;
Set<String> recordExceptionHistory= null;
WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
if (null == instance){
recordExceptionHistory = sGlobalExceptionRecord;
}else {
recordExceptionHistory = instance.getApmForInstance().exceptionRecord;
}
if (null == recordExceptionHistory){
return true;
}
if (recordExceptionHistory.contains(targetException)){
return false;
}
recordExceptionHistory.add(targetException);
return true;
}
/**
* commitCriticalExceptionRT eg:JsRuntime Exception or JsFramework Init Exception
* @param instanceId
* @param errCode
* @param function
* @param exception
* @param extParams
*/
public static void commitCriticalExceptionRT(@Nullable final String instanceId,
@Nullable final WXErrorCode errCode,
@Nullable final String function,
@Nullable final String exception,
@Nullable final Map<String,String> extParams ) {
try {
WXLogUtils.e("weex","commitCriticalExceptionRT :"+errCode+"exception"+exception);
WXStateRecord.getInstance().recordException(instanceId,exception);
IWXConfigAdapter configAdapter = WXSDKManager.getInstance().getWxConfigAdapter();
boolean doCheck = true;
if (null != configAdapter){
String value = configAdapter.getConfig("wxapm","check_repeat_report","true");
doCheck = "true".equalsIgnoreCase(value);
}
boolean doReport =true;
if (doCheck){
doReport = checkNeedReportCauseRepeat(instanceId,errCode,exception);
}
if (!doReport){
return;
}
}catch (Throwable e){
e.printStackTrace();
}
commitCriticalExceptionWithDefaultUrl(
"BundleUrlDefault",
instanceId,
errCode,
function,
exception,
extParams
);
}
public static void commitCriticalExceptionWithDefaultUrl(
@Nullable final String defaultUrl,
@Nullable final String instanceId,
@Nullable final WXErrorCode errCode,
@Nullable final String function,
@Nullable final String exception,
@Nullable final Map<String,String> extParams
){
IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter();
WXSDKInstance instance = null;
WXJSExceptionInfo exceptionCommit;
String bundleUrlCommit = TextUtils.isEmpty(defaultUrl)?"BundleUrlDefault":defaultUrl;
String instanceIdCommit = "InstanceIdDefalut";
String exceptionMsgCommit = exception;
Map<String, String> commitMap = extParams;
if (null == commitMap){
commitMap = new HashMap<>();
}
commitMap.put("wxSdkInitStartTime", String.valueOf(WXEnvironment.sSDKInitStart));
commitMap.put("wxSDKInitCostTime", String.valueOf(WXEnvironment.sSDKInitTime));
commitMap.put("wxSDKCurExceptionTime", String.valueOf(System.currentTimeMillis()));
commitMap.put("wxUseRuntimeApi",String.valueOf(WXEnvironment.sUseRunTimeApi));
if (!TextUtils.isEmpty(instanceId)) {
instanceIdCommit = instanceId;
instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
if (null != instance) {
bundleUrlCommit = instance.getApmForInstance().reportPageName;
Object loadLength = instance.getApmForInstance().extInfo.get(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH);
String loadLengthStr = (loadLength instanceof Integer)?String.valueOf(loadLength):"unknownLength";
commitMap.put(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH,loadLengthStr);
commitMap.put("templateInfo",instance.getTemplateInfo());
if (TextUtils.isEmpty(bundleUrlCommit) || bundleUrlCommit.equals(WXPerformance.DEFAULT)) {
if (!TextUtils.equals(degradeUrl, "BundleUrlDefaultDegradeUrl")) {
bundleUrlCommit = degradeUrl;
} else
bundleUrlCommit = WXSDKInstance.requestUrl;
}
for (Map.Entry<String,String> entry: instance.getContainerInfo().entrySet()){
commitMap.put(entry.getKey(),entry.getValue());
}
commitMap.put("wxStageList",convertStageToStr(instance));
String bundleTemplate = instance.getTemplate();
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.getApmForInstance().stageMap.get(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START);
if (null == pageStartTime){
pageStartTime = instance.getApmForInstance().stageMap.get(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) {
bundleUrlCommit = TextUtils.isEmpty(commitMap.get("weexUrl")) ? commitMap.get("weexUrl")
: commitMap.get("bundleUrl");
}
}
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);
}
WXAnalyzerDataTransfer.transferError(exceptionCommit, instanceId);
}
private static String convertStageToStr(WXSDKInstance instance) {
if (null == instance || null == instance.getApmForInstance() || instance.getApmForInstance().stageMap.isEmpty()) {
return "noStageRecord";
}
List<Entry<String, Long>> list = new ArrayList<>(instance.getApmForInstance().stageMap.entrySet());
Collections.sort(list, new Comparator<Entry<String, Long>>() {
@Override
public int compare(Entry<String, Long> o1, Entry<String, Long> o2) {
return (int)(o1.getValue() - o2.getValue());
}
});
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, Long> entry : list) {
builder.append(entry.getKey()).append(':').append(entry.getValue()).append("->");
}
return builder.toString();
}
}