上一篇文章已经分析了内存的监控原理,现在来分析网络IO的原理和技巧。
网络通讯,本质上是IO流的处理。既然是IO方面的内容,那么就有输入和输出,就可以在整个过程中进行拦截,获取我们想要的信息。目前这个组件只针对普通Http/Https通讯进行拦截获取数据,所以数据来自于Http包体的各种信息(Header、Request、Response等)。另外网络通讯框架用的是OKHttp,相信绝大多数的Android网络通讯框架都是这个,所以主要实现方式是通过增加自定义的拦截器,获得通讯过程中的各项数据。
OKHttp怎么增加自己编写的拦截器,请自行百度...
1、实现自定义拦截器
private OkHttpData okHttpData;
@Override
public Response intercept(Chain chain) throws IOException {
long startNs = System.currentTimeMillis();
okHttpData = new OkHttpData();
okHttpData.startTime = startNs;
if (Manager.isDebug()) {
ApmLogX.i(APM_TAG, SUB_TAG, "okhttp request startTime:" + TimeUtils.getFormatTime(okHttpData.startTime, TimeUtils.DATETIMEMILLIS_SPLIT));
}
Request request = chain.request();
recordRequestData(request);
Response response;
try {
response = chain.proceed(request);
} catch (IOException e) {
if (Manager.isDebug()) {
e.printStackTrace();
ApmLogX.e(APM_TAG, SUB_TAG, "http faild:" + e.getMessage());
}
okHttpData.errorMessage = e.getMessage();
DataRecordUtils.recordNetinfo(okHttpData);
throw e;
}
okHttpData.costTime = System.currentTimeMillis() - startNs;
if (Manager.isDebug()) {
ApmLogX.e(APM_TAG, SUB_TAG, "request costTime:" + TimeUtils.millsToTime(okHttpData.costTime));
}
recordResponseData(response);
if (Manager.isDebug()) {
ApmLogX.d(APM_TAG, SUB_TAG, "okhttp chain.proceed end");
}
DataRecordUtils.recordNetinfo(okHttpData);
return response;
}
private void recordRequestData(Request request) {
if (null == request ||
null == request.url() ||
TextUtils.isEmpty(request.url().toString())) {
return;
}
okHttpData.url = request.url().toString();
okHttpData.headers = request.headers().toString();
okHttpData.method = request.method();
if (Manager.isDebug()) {
ApmLogX.d(APM_TAG, SUB_TAG, "okhttp request url:" + okHttpData.url);
ApmLogX.d(APM_TAG, SUB_TAG, "okhttp request headers:\n" + okHttpData.headers);
ApmLogX.d(APM_TAG, SUB_TAG, "okhttp request method:" + okHttpData.method);
}
RequestBody requestBody = request.body();
if (requestBody == null) {
okHttpData.requestSize = request.url().toString().getBytes().length;
if (Manager.isDebug()) {
ApmLogX.d(APM_TAG, SUB_TAG, "okhttp request upload datasize:" + okHttpData.requestSize + " byte");
}
return;
}
long contentLength = 0;
try {
contentLength = requestBody.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
if (contentLength > 0) {
okHttpData.requestSize = contentLength;
} else {
okHttpData.requestSize = request.url().toString().getBytes().length;
}
}
private void recordResponseData(Response response) {
if (response == null) {
return;
}
okHttpData.responseCode = response.code();
if (Manager.isDebug()) {
ApmLogX.d(APM_TAG, SUB_TAG, "okhttp response code:" + okHttpData.responseCode);
}
ResponseBody responseBody = response.body();
if (responseBody == null) {
return;
}
long contentLength = responseBody.contentLength();
if (contentLength > 0) {
if (Manager.isDebug()) {
ApmLogX.d(APM_TAG, SUB_TAG, "直接通过responseBody取到contentLength:" + contentLength + " byte");
}
} else {
BufferedSource source = responseBody.source();
if (source != null) {
try {
source.request(Long.MAX_VALUE);
} catch (IOException e) {
e.printStackTrace();
}
Buffer buffer = source.buffer();
contentLength = buffer.size();
if (Manager.isDebug()) {
ApmLogX.e(APM_TAG, SUB_TAG, "通过responseBody.source()取到contentLength:" + contentLength + " byte");
}
}
}
okHttpData.responseSize = contentLength;
if (Manager.isDebug()) {
ApmLogX.d(APM_TAG, SUB_TAG, "okhttp response download size:" + okHttpData.responseSize + " byte" );
}
}
我觉得监控网络的数据真的超简单的,OkHttpData是一个数据实体,里面定义各种想保存的数据属性。在chain.proceed前记录上行数据,包括header、url、method、参数、数据量大小等。在chain.proceed后记录下行数据,包括返回码、返回数据大小、返回数据内容等。拿到这些数据后,后面的处理逻辑就悉随君便了...
这是第五篇分析文章,核心功能已经分析完了,剩下的就是拿到数据之后存储、上报、旧数据清理等的功能,这里不赘述。写程序、做功能,不应只停留在把这个功能写完了,测试测过能通就算完成了,还要关注整个过程的数据细节,是不是有哪些地方做得不足,还可以改善,能不能协同其他部门一起把事情处理成一个闭环,让整个业务在这个闭环内流畅运转,从而产生实际收益,这才是一个专业的技术人员应有的职业素养及眼光。而不是慵懒、狭隘地认为只要做完功能就好了,多一步都不去想,拿工资就完事。最终受损的还是你自己,企业一直在向上,而你却原地转圈......
网友评论