美文网首页
DevTool中,OkHttp 添加 EventListener

DevTool中,OkHttp 添加 EventListener

作者: perry_Fan | 来源:发表于2022-11-30 13:40 被阅读0次

    一. 说明

    凡添加有 StethoNetworkTool.isEnabled 判别处,均需要增加。
    另外以下三方法需增加
    generateTraceData()saveEvent(String eventName)saveUrl(String url)

    二. 代码实践

    package base.library.net.http.analysis;
    
    
    import android.os.SystemClock;
    import android.util.Log;
    
    import com.google.gson.Gson;
    import com.sensorsdata.analytics.android.sdk.SensorsDataAPI;
    import com.yh.base.lib.utils.GsonUtil;
    import com.yh.base.lib.utils.StringUtils;
    import com.yonghui.yhlocaltool.stetho.data.IDataPoolHandleImpl;
    import com.yonghui.yhlocaltool.stetho.data.NetworkTraceBean;
    import com.yonghui.yhlocaltool.stetho.utils.StethoNetworkTool;
    import com.yonghui.yhlocaltool.stetho.utils.StethoNetworkUtils;
    
    import org.jetbrains.annotations.NotNull;
    import org.json.JSONObject;
    
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.net.Proxy;
    import java.net.URI;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.atomic.AtomicInteger;
    
    import base.library.net.http.HttpConstants;
    import io.sentry.Scope;
    import io.sentry.ScopeCallback;
    import io.sentry.Sentry;
    import okhttp3.Call;
    import okhttp3.Connection;
    import okhttp3.EventListener;
    import okhttp3.Handshake;
    import okhttp3.HttpUrl;
    import okhttp3.Protocol;
    import okhttp3.Request;
    import okhttp3.Response;
    
    public class AnalysisEventListener extends EventListener {
        private static final String TAG = "NetworkEventListener";
    
        private static AtomicInteger mNextRequestId = new AtomicInteger(0);
        private String mRequestId ;
    
        public interface Callback {
            class Rsp {
                public int code;//ac
                public String message;//ac
            }
    
            boolean isSuccessResponse(int code);
    
            Rsp parseRsp(String response) throws Exception;
        }
    
        static Callback callback = null;
    
        static ConcurrentHashMap<Call, NetEvent> eventMap = new ConcurrentHashMap<>();
    
        public static void setCallback(Callback callback) {
            AnalysisEventListener.callback = callback;
        }
    
        public static void onResponse(Call call, String resps) {
    //        //Log.v("zzy", "onResponse:" + resps);
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.resps = resps;
            }
        }
    
        @Override
        public void callStart(Call call) {
            //Log.v("zzy", "callStart:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = new NetEvent();
            event.fs = System.currentTimeMillis();//接口请求时间点
            Request request = call.request();
            if (request != null) {
                HttpUrl url = request.url();
                if (url != null) {
                    URI uri = url.uri();
                    event.scheme = uri.getScheme();
                    event.host = getRealHost(uri.getHost());
                    event.path = getRealPath(uri.getPath());
                }
            }
            if (eventMap.size() > 100)
                eventMap.clear();
    //        event.transaction = Sentry.startTransaction("networkAnalysis","op",(String)null);
    //        event.span = transaction.startChild("network11");
            eventMap.put(call, event);
    
    
            if (StethoNetworkTool.isEnabled){
                //mRequestId = mNextRequestId.getAndIncrement() + "";
                //getAndAdd,在多线程下使用cas保证原子性
                mRequestId = String.valueOf(mNextRequestId.getAndIncrement());
                Log.i(TAG,TAG+"-------callStart---requestId-----"+mRequestId);
                saveEvent(NetworkTraceBean.CALL_START);
                saveUrl(call.request().url().toString());
            }
        }
    
        private String getRealHost(String host) {
            if (host.contains(HttpConstants.IS_OLD_FRAMEWORK)) {
                return host.replace(HttpConstants.IS_OLD_FRAMEWORK, "");
            }
            return host;
        }
    
        private String getRealPath(String path) {
            if (path.contains(HttpConstants.IS_OLD_FRAMEWORK)) {
                return path.replace(HttpConstants.IS_OLD_FRAMEWORK + "/", "");
            }
            return path;
        }
    
        @Override
        public void callFailed(Call call, IOException ioe) {
            //Log.v("zzy", "callFailed:" + System.currentTimeMillis() + " " + call.request().url());
            if (isCacheCall(call)) {
                return;
            }
            onFailed(call, ioe);
        }
    
        private void onFailed(Call call, Exception ioe) {
            NetEvent event = eventMap.remove(call);
            if (event != null) {
                try {
                    event.du = (int) (System.currentTimeMillis() - event.fs);
                    event.query = call.request().url().query();
                    event.res = HttpHelper.getBodyString(call.request().body());
                    event.resps = ioe.toString();
                    doSensors(event);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        void doSensors(NetEvent event) {
            String str;
            str = event.res;
            if (str != null && str.length() > 1024) {
                str = str.substring(0, 1024);
                event.res = str;
            }
            str = event.resps;
            if (str != null && str.length() > 1024) {
                str = str.substring(0, 1024);
                event.resps = str;
            }
            str = event.query;
            if (str != null && str.length() > 1024) {
                str = str.substring(0, 1024);
                event.query = str;
            }
            try {
    //            ITransaction transaction = event.transaction;
    //            event.transaction = null;
                if(event.sc==200&&(callback==null||callback.isSuccessResponse(event.ac)))//正常的数据不统计
                    return;
    //            Map<String, Object> map = GsonUtil.fromJson(GsonUtil.toJson(event), HashMap.class);
    //            Iterator<String> it = map.keySet().iterator();
    //            while (it.hasNext()) {
    //                String key = it.next();
    //                String value = map.get(key).toString();
    //                transaction.setData(key, value);
    //                transaction.setTag(key, value);
    //            }
    //            if(event.du!=null)
    //                transaction.setMeasurement("fp", event.du, MeasurementUnit.Duration.MILLISECOND);
    //            transaction.finish();
                Sentry.captureMessage("networkAnalysis", new ScopeCallback() {
                    @Override
                    public void run(@NotNull Scope scope) {
                        Map<String, Object> map = GsonUtil.fromJson(GsonUtil.toJson(event), HashMap.class);
                        Iterator<String> it = map.keySet().iterator();
                        while (it.hasNext()) {
                            String key = it.next();
                            String value = map.get(key).toString();
                            scope.setExtra(key, value);
                            scope.setTag(key, value);
                        }
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            try {
                SensorsDataAPI.sharedInstance().track("networkAnalysis", new JSONObject(new Gson().toJson(event)));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void callEnd(Call call) {
    //        Log.v("zzy", "callEnd:" + System.currentTimeMillis() + " " + call.request().url());
            if (isCacheCall(call)) {
                return;
            }
    //        Log.v("zzy", "callEnd:" + call.request().url()+"====我不是缓存");
            NetEvent event = eventMap.remove(call);
            if (event != null && (event.rs != null || event.rsps != null)) {
                try {
                    event.du = (int) (System.currentTimeMillis() - event.fs);
                    if (event.sc != null && event.sc == 200) {
                        event.query = call.request().url().query();
                        event.res = HttpHelper.getBodyString(call.request().body());
                        if (callback != null) {
                            try {
                                Callback.Rsp rep = callback.parseRsp(event.resps);
                                event.ac = rep.code;
                                if (callback.isSuccessResponse(rep.code)) {
    //                                event.query = null;
    //                                event.res = null;
    //                                event.resps = null;
                                }
                            } catch (Exception ignored) {
                            }
                        }
                    }
                    //Log.v("zzy", "callEnd: du=" + event.du);
                    doSensors(event);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            if (StethoNetworkTool.isEnabled){
                saveEvent(NetworkTraceBean.CALL_END);
                generateTraceData();
                StethoNetworkUtils.timeoutChecker(mRequestId);
            }
    
        }
    
        /**
         * 是否是缓存请求  true:是
         * @param call
         * @return
         */
        private boolean isCacheCall(Call call) {
            String yhCacheModel = call.request().header("YHCacheModel");
            if (!StringUtils.isNullOrEmpty(yhCacheModel)) {
                try {
                    int cacheMode = Integer.parseInt(yhCacheModel);
                    if (cacheMode > 0) {
                        return true;
                    }
                } catch (NumberFormatException e) {
    
                }
            }
            return false;
        }
    
        @Override
        public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) {
            //Log.v("zzy", "connectStart:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.cs = System.currentTimeMillis();//HTTP建链开始时间点
            }
    
            saveEvent(NetworkTraceBean.CONNECT_START);
        }
    
        @Override
        public void connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol, IOException ioe) {
            Log.v("zzy", "connectFailed:" + System.currentTimeMillis() + " " + call.request().url());
        }
    
        @Override
        public void connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol) {
            //Log.v("zzy", "connectEnd:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.ce = System.currentTimeMillis();//HTTP建链完成时间
                if (event.cs != null)
                    event.cn = (int) (event.ce - event.cs);//HTTP链接整体耗时
            }
    
            saveEvent(NetworkTraceBean.CONNECT_END);
        }
    
        @Override
        public void dnsStart(Call call, String domainName) {
            //Log.v("zzy", "dnsStart:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.ds = System.currentTimeMillis();//DNS开始时间点
            }
            saveEvent(NetworkTraceBean.DNS_START);
        }
    
        @Override
        public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
            //Log.v("zzy", "dnsEnd:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.de = System.currentTimeMillis();//DNS结束时间点
                if (event.ds != null)
                    event.dns = (int) (event.de - event.ds);//DNS 耗时,单位ms
            }
            saveEvent(NetworkTraceBean.DNS_END);
        }
    
        @Override
        public void secureConnectStart(Call call) {
            //Log.v("zzy", "secureConnectStart:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.scs = System.currentTimeMillis();//TLS开始时间点,timestamp
            }
            saveEvent(NetworkTraceBean.SECURE_CONNECT_START);
        }
    
        @Override
        public void secureConnectEnd(Call call, Handshake handshake) {
            //Log.v("zzy", "secureConnectEnd:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.sce = System.currentTimeMillis();// TLS结束时间点,timestamp|
                if (event.scs != null)
                    event.tls = (int) (event.sce - event.scs);//TLS 耗时,单位ms
            }
            saveEvent(NetworkTraceBean.SECURE_CONNECT_END);
        }
    
        @Override
        public void connectionReleased(Call call, Connection connection) {
            //Log.v("zzy", "connectionReleased:" + System.currentTimeMillis() + " " + call.request().url());
        }
    
        @Override
        public void requestHeadersStart(Call call) {
            //Log.v("zzy", "requestHeadersStart:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.rs = System.currentTimeMillis();// 接口请求时间点 开始
            }
            saveEvent(NetworkTraceBean.REQUEST_HEADERS_START);
        }
    
        @Override
        public void requestHeadersEnd(Call call, Request request) {
            //Log.v("zzy", "requestHeadersEnd:" + System.currentTimeMillis() + " " + call.request().url());
            saveEvent(NetworkTraceBean.REQUEST_HEADERS_END);
        }
    
        @Override
        public void requestBodyStart(Call call) {
            //Log.v("zzy", "requestBodyStart:" + System.currentTimeMillis() + " " + call.request().url());
            saveEvent(NetworkTraceBean.REQUEST_BODY_START);
        }
    
        @Override
        public void requestFailed(Call call, IOException ioe) {
            //Log.v("zzy", "requestFailed:" + System.currentTimeMillis() + " " + call.request().url());
        }
    
        @Override
        public void requestBodyEnd(Call call, long byteCount) {
            //Log.v("zzy", "requestBodyEnd:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.ree = System.currentTimeMillis();// 接口请求时间点 结束
                if (event.rs != null)
                    event.re = (int) (event.ree - event.rs);//请求耗时
            }
            saveEvent(NetworkTraceBean.REQUEST_BODY_END);
        }
    
        @Override
        public void responseHeadersStart(Call call) {
            //Log.v("zzy", "responseHeadersStart:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.rsps = System.currentTimeMillis();//首包开始时间点
            }
            saveEvent(NetworkTraceBean.RESPONSE_HEADERS_START);
        }
    
        @Override
        public void responseHeadersEnd(Call call, Response response) {
            //Log.v("zzy", "responseHeadersEnd:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.sc = response.code();//HTTP状态码,如200
                event.np = response.protocol().name();
            }
            saveEvent(NetworkTraceBean.RESPONSE_HEADERS_END);
        }
    
        @Override
        public void responseBodyStart(Call call) {
            //Log.v("zzy", "responseBodyStart:" + System.currentTimeMillis() + " " + call.request().url());
            saveEvent(NetworkTraceBean.RESPONSE_BODY_START);
        }
    
        @Override
        public void responseFailed(Call call, IOException ioe) {
            //Log.v("zzy", "responseFailed:" + System.currentTimeMillis() + " " + call.request().url());
        }
    
        @Override
        public void responseBodyEnd(Call call, long byteCount) {
            //Log.v("zzy", "responseBodyEnd:" + System.currentTimeMillis() + " " + call.request().url());
            NetEvent event = eventMap.get(call);
            if (event != null) {
                event.rspe = System.currentTimeMillis();//首包结束时间点
                if (event.rsps != null) {
                    event.resp = (int) (event.rspe - event.rsps);//首包接收耗时
                }
            }
            saveEvent(NetworkTraceBean.RESPONSE_BODY_END);
        }
    
    
    
        private void generateTraceData(){
            NetworkTraceBean traceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
            Map<String, Long> eventsTimeMap = traceModel.getNetworkEventsMap();
            Map<String, Long> traceList = traceModel.getTraceItemList();
            traceList.put(NetworkTraceBean.TRACE_NAME_TOTAL, StethoNetworkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.CALL_START, NetworkTraceBean.CALL_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_DNS,StethoNetworkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.DNS_START, NetworkTraceBean.DNS_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_SECURE_CONNECT,StethoNetworkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.SECURE_CONNECT_START, NetworkTraceBean.SECURE_CONNECT_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_CONNECT,StethoNetworkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.CONNECT_START, NetworkTraceBean.CONNECT_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_REQUEST_HEADERS,StethoNetworkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.REQUEST_HEADERS_START, NetworkTraceBean.REQUEST_HEADERS_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_REQUEST_BODY,StethoNetworkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.REQUEST_BODY_START, NetworkTraceBean.REQUEST_BODY_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_RESPONSE_HEADERS,StethoNetworkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.RESPONSE_HEADERS_START, NetworkTraceBean.RESPONSE_HEADERS_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_RESPONSE_BODY,StethoNetworkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.RESPONSE_BODY_START, NetworkTraceBean.RESPONSE_BODY_END));
            traceModel.setTraceItemList(traceList);
        }
    
        private void saveEvent(String eventName){
            if (StethoNetworkTool.isEnabled){
                NetworkTraceBean networkTraceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
                Map<String, Long> networkEventsMap = networkTraceModel.getNetworkEventsMap();
                networkEventsMap.put(eventName, SystemClock.elapsedRealtime());
                networkTraceModel.setNetworkEventsMap(networkEventsMap);
            }
        }
    
        private void saveUrl(String url){
            if (StethoNetworkTool.isEnabled){
                NetworkTraceBean networkTraceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
                networkTraceModel.setUrl(url);
            }
        }
    
    }
    
    

    相关文章

      网友评论

          本文标题:DevTool中,OkHttp 添加 EventListener

          本文链接:https://www.haomeiwen.com/subject/xkfsfdtx.html