前言
移动互联网时代,极大部分的APP都需要依赖Server来获取数据,如果因为网络请求慢或者请求失败,导致用户无法顺畅的使用业务功能,会对用户体验造成极大影响。所以我们应该尽可能的监控网络请求的各个阶段,以准对不同问题进行优化。
需求分析
1. 上图是okhttp网络请求的各个阶段针对上图我们知道我们大概要采集下述各个阶段的耗时数据:
- 整个网络请求耗时
- dns耗时
- 建连耗时
- TCP建连耗时
- TLS建连耗时
- 数据上行耗时
- header上行耗时
- body上行耗时
- 数据下行耗时
- header下行耗时
- body下行耗时
2. 除此之外我们还需要一些通用数据来辅助我们排查问题
- 请求url:请求url。
- 请求方式 : get , post ....
- 是否Https:
- 是否开了代理:
- 上行流量:包括整个请求上行header和body的总的流量,包含重试和重定向的上行流量。用于监控上行流量开销。
- 下行流量:包括整个请求下行header和body的总的流量,包含重试和重定向的下行流量。用于监控下行流量开销。
- 目标IP地址:对于多出口IP的客户,支持IP地址维度的数据分析。
- dns解析结果:请求url的域名解析ip列表,用于分析是否存在域名劫持的问题。
- tls握手记录:用于排查问题
- http code:根据http code确定请求状态。
- 网络库类型及版本:对于客户更换网络库或者升级网络库版本的情况,可以提供前后的网络数据的差异。
- 网络状态:NO,2G,3G,4G,5G,WIFI
- 异常信息:异常信息主要是收集网络请求各阶段出现异常时的异常栈的信息。比如常见的java.net.UnknownHostException、java.net.SocketTimeoutException等。
实现
从上面的需求看来我们需要获取的信息还是蛮多的,那我们该如何去获取呢?很幸运 okhttp 给我们提供了 EventListener
来专门让我们 监听 网络请求的各个阶段数据。如下是 对 EventListener
的官方描述
Listener for metrics events. Extend this class to monitor the quantity, size, and duration of your application's HTTP calls.
EventListener
中提供了很多的回调方法,基本上和上面图片中的各个阶段是吻合的。
EventListener.class
public abstract class EventListener {
public void callStart(Call call) { }
public void dnsStart(Call call, String domainName) { }
public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) { }
public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) { }
public void secureConnectStart(Call call) { }
public void secureConnectEnd(Call call, @Nullable Handshake handshake) { }
public void connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy,
@Nullable Protocol protocol) { }
public void connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy,
@Nullable Protocol protocol, IOException ioe) {}
public void connectionAcquired(Call call, Connection connection) { }
public void connectionReleased(Call call, Connection connection) { }
public void requestHeadersStart(Call call) { }
public void requestHeadersEnd(Call call, Request request) { }
public void requestBodyStart(Call call) { }
public void requestBodyEnd(Call call, long byteCount) { }
public void requestFailed(Call call, IOException ioe) { }
public void responseHeadersStart(Call call) { }
public void responseHeadersEnd(Call call, Response response) { }
public void responseBodyStart(Call call) {}
public void responseBodyEnd(Call call, long byteCount) { }
public void responseFailed(Call call, IOException ioe) {}
public void callEnd(Call call) { }
public void callFailed(Call call, IOException ioe) {}
}
有了这个神器,那我们只需要直接实现就行了,具体代码存放在GitHub 只有关键类,有报错的地方,稍微改一下就ok 了。
写在后面
如果想监控Retrofit数据解析过程可以参考我的文章 Retrofit 数据解析 监控