一. 说明
凡添加有 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);
}
}
}
网友评论