1、Events
Events允许捕获应用程序的HTTP调用的指标,可以使用事件来监控以下参数:
- 应用发起的HTTP请求大小及频率
- 请求在底层网络上的性能
2、EventListener
-
在没有经过重定向和重试的网络请求数据流程图:
-
EventListener使用示例代码
class OkEventListener : EventListener() {
private val TAG = "tag"
private var callStartTime: Long = 0
override fun callStart(call: Call) {
super.callStart(call)
callStartTime = System.currentTimeMillis()
mLog("callStart url=== ${call.request().url}")
}
override fun callEnd(call: Call) {
super.callEnd(call)
printEvent("callEnd url===${call.request().url}")
}
override fun dnsStart(call: Call, domainName: String) {
super.dnsStart(call, domainName)
printEvent("dnsStart")
}
override fun dnsEnd(call: Call, domainName: String, inetAddressList: List<InetAddress>) {
super.dnsEnd(call, domainName, inetAddressList)
printEvent("dnsEnd")
}
override fun connectStart(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy) {
super.connectStart(call, inetSocketAddress, proxy)
printEvent("connectStart")
}
override fun connectEnd(
call: Call,
inetSocketAddress: InetSocketAddress,
proxy: Proxy,
protocol: Protocol?
) {
super.connectEnd(call, inetSocketAddress, proxy, protocol)
printEvent("connectEnd")
}
override fun connectionReleased(call: Call, connection: Connection) {
super.connectionReleased(call, connection)
printEvent("connectionReleased")
}
override fun connectFailed(
call: Call,
inetSocketAddress: InetSocketAddress,
proxy: Proxy,
protocol: Protocol?,
ioe: IOException
) {
super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe)
printEvent("connectFailed")
}
override fun requestHeadersStart(call: Call) {
super.requestHeadersStart(call)
printEvent("requestHeadersStart")
}
override fun requestHeadersEnd(call: Call, request: Request) {
super.requestHeadersEnd(call, request)
printEvent("requestHeadersEnd")
}
override fun requestBodyStart(call: Call) {
super.requestBodyStart(call)
printEvent("requestBodyStart")
}
override fun requestBodyEnd(call: Call, byteCount: Long) {
super.requestBodyEnd(call, byteCount)
printEvent("requestBodyEnd")
}
override fun requestFailed(call: Call, ioe: IOException) {
super.requestFailed(call, ioe)
printEvent("requestBodyFailed")
}
override fun responseHeadersStart(call: Call) {
super.responseHeadersStart(call)
printEvent("responseHeadersStart")
}
override fun responseHeadersEnd(call: Call, response: Response) {
super.responseHeadersEnd(call, response)
printEvent("responseHeadersEnd")
}
override fun responseBodyStart(call: Call) {
super.responseBodyStart(call)
printEvent("responseBodyStart")
}
override fun responseBodyEnd(call: Call, byteCount: Long) {
super.responseBodyEnd(call, byteCount)
printEvent("responseBodyEnd")
}
private fun printEvent(name: String) {
val elapsedTime: Long = System.currentTimeMillis() - callStartTime
mLog("time=== $elapsedTime ms name=== $name")
}
private fun mLog(str: String) {
Log.d(TAG, str)
}
}
- 同一个请求get和post请求日志
2021-07-06 17:50:54.065 28217-28217/com.example.myapplication D/tag: callStart url=== https://publicobject.com/helloworld.txt
2021-07-06 17:50:54.068 28217-28672/com.example.myapplication D/tag: time=== 3 ms name=== dnsStart
2021-07-06 17:50:54.073 28217-28672/com.example.myapplication D/tag: time=== 8 ms name=== dnsEnd
2021-07-06 17:50:54.073 28217-28672/com.example.myapplication D/tag: time=== 8 ms name=== connectStart
2021-07-06 17:50:54.461 28217-28672/com.example.myapplication D/tag: time=== 396 ms name=== connectEnd
2021-07-06 17:50:54.462 28217-28672/com.example.myapplication D/tag: time=== 397 ms name=== requestHeadersStart
2021-07-06 17:50:54.462 28217-28672/com.example.myapplication D/tag: time=== 397 ms name=== requestHeadersEnd
2021-07-06 17:50:54.922 28217-28672/com.example.myapplication D/tag: time=== 857 ms name=== responseHeadersStart
2021-07-06 17:50:54.922 28217-28672/com.example.myapplication D/tag: time=== 857 ms name=== responseHeadersEnd
2021-07-06 17:50:54.923 28217-28672/com.example.myapplication D/tag: get success response=== okhttp3.internal.http.RealResponseBody@326b64a
2021-07-06 17:50:56.015 28217-28217/com.example.myapplication D/tag: callStart url=== https://publicobject.com/helloworld.txt
2021-07-06 17:50:56.020 28217-28672/com.example.myapplication D/tag: time=== 6 ms name=== dnsStart
2021-07-06 17:50:56.020 28217-28672/com.example.myapplication D/tag: time=== 6 ms name=== dnsEnd
2021-07-06 17:50:56.021 28217-28672/com.example.myapplication D/tag: time=== 7 ms name=== connectStart
2021-07-06 17:50:56.429 28217-28672/com.example.myapplication D/tag: time=== 415 ms name=== connectEnd
2021-07-06 17:50:56.430 28217-28672/com.example.myapplication D/tag: time=== 416 ms name=== requestHeadersStart
2021-07-06 17:50:56.431 28217-28672/com.example.myapplication D/tag: time=== 417 ms name=== requestHeadersEnd
2021-07-06 17:50:56.870 28217-28672/com.example.myapplication D/tag: time=== 856 ms name=== responseHeadersStart
2021-07-06 17:50:56.870 28217-28672/com.example.myapplication D/tag: time=== 856 ms name=== responseHeadersEnd
2021-07-06 17:50:56.871 28217-28672/com.example.myapplication D/tag: post success response=== okhttp3.internal.http.RealResponseBody@3b2d697
3、EventListener.Factory
在前面的示例中,我们使用了一个callStartNanos来跟踪每个事件的运行时间。这很方便,但是如果多个Call请求同时执行,由于不能区分请求url生命周期,就会有问题了。为了适应这种情况,可以使用Factory为每个Call创建一个新的EventListener实例,可以实现每个listener保持特定于调用的状态。
- OkEventFactoryListener
class OkEventFactoryListener(callId:Long,startTime:Long) : EventListener() {
private val TAG = "factory"
private var mCallStartNanos: Long = startTime
private val mCallId=callId
override fun callStart(call: Call) {
super.callStart(call)
printEvent("callStart")
}
override fun callEnd(call: Call) {
super.callEnd(call)
printEvent("callEnd")
}
override fun dnsStart(call: Call, domainName: String) {
super.dnsStart(call, domainName)
printEvent("dnsStart")
}
override fun dnsEnd(call: Call, domainName: String, inetAddressList: List<InetAddress>) {
super.dnsEnd(call, domainName, inetAddressList)
printEvent("dnsEnd")
}
override fun connectStart(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy) {
super.connectStart(call, inetSocketAddress, proxy)
printEvent("connectStart")
}
override fun connectEnd(
call: Call,
inetSocketAddress: InetSocketAddress,
proxy: Proxy,
protocol: Protocol?
) {
super.connectEnd(call, inetSocketAddress, proxy, protocol)
printEvent("connectEnd")
}
override fun connectionReleased(call: Call, connection: Connection) {
super.connectionReleased(call, connection)
printEvent("connectionReleased")
}
override fun connectFailed(
call: Call,
inetSocketAddress: InetSocketAddress,
proxy: Proxy,
protocol: Protocol?,
ioe: IOException
) {
super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe)
printEvent("connectFailed")
}
override fun requestHeadersStart(call: Call) {
super.requestHeadersStart(call)
printEvent("requestHeadersStart")
}
override fun requestHeadersEnd(call: Call, request: Request) {
super.requestHeadersEnd(call, request)
printEvent("requestHeadersEnd")
}
override fun requestBodyStart(call: Call) {
super.requestBodyStart(call)
printEvent("requestBodyStart")
}
override fun requestBodyEnd(call: Call, byteCount: Long) {
super.requestBodyEnd(call, byteCount)
printEvent("requestBodyEnd")
}
override fun requestFailed(call: Call, ioe: IOException) {
super.requestFailed(call, ioe)
printEvent("requestBodyFailed")
}
override fun responseHeadersStart(call: Call) {
super.responseHeadersStart(call)
printEvent("responseHeadersStart")
}
override fun responseHeadersEnd(call: Call, response: Response) {
super.responseHeadersEnd(call, response)
printEvent("responseHeadersEnd")
}
override fun responseBodyStart(call: Call) {
super.responseBodyStart(call)
printEvent("responseBodyStart")
}
override fun responseBodyEnd(call: Call, byteCount: Long) {
super.responseBodyEnd(call, byteCount)
printEvent("responseBodyEnd")
}
private fun printEvent(name: String) {
val elapsedTime: Long = System.currentTimeMillis() - mCallStartNanos
mLog("callId== $mCallId time=== $elapsedTime ms name=== $name")
}
private fun mLog(str: String) {
Log.d(TAG, str)
}
companion object {
private val nextCallId: AtomicLong = AtomicLong(1L)
fun create(): Factory {
return object : Factory {
override fun create(call: Call): EventListener {
val callId: Long = nextCallId.getAndIncrement()
Log.d("factory", "callId== $callId url==${call.request().url}")
return OkEventFactoryListener(callId,System.currentTimeMillis())
}
}
}
}
}
- 请求日志
2021-07-06 17:55:26.587 29140-29140/com.example.myapplication D/factory: callId== 1 url==https://publicobject.com/helloworld.txt
2021-07-06 17:55:26.588 29140-29140/com.example.myapplication D/factory: callId== 1 time=== 1 ms name=== callStart
2021-07-06 17:55:26.603 29140-29248/com.example.myapplication D/factory: callId== 1 time=== 16 ms name=== dnsStart
2021-07-06 17:55:26.607 29140-29248/com.example.myapplication D/factory: callId== 1 time=== 20 ms name=== dnsEnd
2021-07-06 17:55:26.612 29140-29248/com.example.myapplication D/factory: callId== 1 time=== 25 ms name=== connectStart
2021-07-06 17:55:27.068 29140-29248/com.example.myapplication D/factory: callId== 1 time=== 481 ms name=== connectEnd
2021-07-06 17:55:27.070 29140-29248/com.example.myapplication D/factory: callId== 1 time=== 483 ms name=== requestHeadersStart
2021-07-06 17:55:27.071 29140-29248/com.example.myapplication D/factory: callId== 1 time=== 484 ms name=== requestHeadersEnd
2021-07-06 17:55:27.438 29140-29248/com.example.myapplication D/factory: callId== 1 time=== 851 ms name=== responseHeadersStart
2021-07-06 17:55:27.439 29140-29248/com.example.myapplication D/factory: callId== 1 time=== 852 ms name=== responseHeadersEnd
2021-07-06 17:55:28.914 29140-29140/com.example.myapplication D/factory: callId== 2 url==https://www.baidu.com/
2021-07-06 17:55:28.914 29140-29140/com.example.myapplication D/factory: callId== 2 time=== 0 ms name=== callStart
2021-07-06 17:55:28.918 29140-29248/com.example.myapplication D/factory: callId== 2 time=== 4 ms name=== dnsStart
2021-07-06 17:55:28.946 29140-29248/com.example.myapplication D/factory: callId== 2 time=== 32 ms name=== dnsEnd
2021-07-06 17:55:28.947 29140-29248/com.example.myapplication D/factory: callId== 2 time=== 33 ms name=== connectStart
2021-07-06 17:55:29.035 29140-29248/com.example.myapplication D/factory: callId== 2 time=== 121 ms name=== connectEnd
2021-07-06 17:55:29.036 29140-29248/com.example.myapplication D/factory: callId== 2 time=== 122 ms name=== requestHeadersStart
2021-07-06 17:55:29.036 29140-29248/com.example.myapplication D/factory: callId== 2 time=== 122 ms name=== requestHeadersEnd
2021-07-06 17:55:29.059 29140-29248/com.example.myapplication D/factory: callId== 2 time=== 145 ms name=== responseHeadersStart
2021-07-06 17:55:29.060 29140-29248/com.example.myapplication D/factory: callId== 2 time=== 146 ms name=== responseHeadersEnd
4、Events with Failures
向服务端发起创建连接失败时,会调用connectFailed(),Http请求永久失败时,会调用callFailed()方法
-
调用流程图如下:
-
connectionFail日志
2021-07-07 12:26:53.019 11814-11984/com.example.myapplication D/tag: get success response=== okhttp3.internal.http.RealResponseBody@cea5bb6
2021-07-07 12:26:59.182 11814-11814/com.example.myapplication D/tag: callStart url=== https://publicobject.com/helloworld.txt
2021-07-07 12:26:59.190 11814-11984/com.example.myapplication D/tag: time=== 8 ms name=== dnsStart
2021-07-07 12:26:59.192 11814-11984/com.example.myapplication D/tag: time=== 10 ms name=== dnsEnd
2021-07-07 12:26:59.193 11814-11984/com.example.myapplication D/tag: time=== 11 ms name=== connectStart
2021-07-07 12:26:59.608 11814-11984/com.example.myapplication D/tag: time=== 426 ms name=== connectEnd
2021-07-07 12:26:59.609 11814-11984/com.example.myapplication D/tag: time=== 427 ms name=== requestHeadersStart
2021-07-07 12:26:59.610 11814-11984/com.example.myapplication D/tag: time=== 428 ms name=== requestHeadersEnd
2021-07-07 12:27:00.138 11814-11984/com.example.myapplication D/tag: time=== 956 ms name=== responseHeadersStart
2021-07-07 12:27:00.138 11814-11984/com.example.myapplication D/tag: time=== 956 ms name=== responseHeadersEnd
2021-07-07 12:27:00.138 11814-11984/com.example.myapplication D/tag: get success response=== okhttp3.internal.http.RealResponseBody@ac3a153
2021-07-07 12:27:07.422 11814-11814/com.example.myapplication D/tag: callStart url=== https://www.nytimes.com/
2021-07-07 12:27:07.432 11814-11984/com.example.myapplication D/tag: time=== 10 ms name=== dnsStart
2021-07-07 12:27:07.498 11814-11984/com.example.myapplication D/tag: time=== 76 ms name=== dnsEnd
2021-07-07 12:27:07.499 11814-11984/com.example.myapplication D/tag: time=== 77 ms name=== connectStart
2021-07-07 12:27:17.512 11814-11984/com.example.myapplication D/tag: time=== 10090 ms name=== connectFailed
2021-07-07 12:27:17.512 11814-11984/com.example.myapplication D/tag: fail e===failed to connect to www.nytimes.com/31.13.87.19 (port 443) from /10.208.95.23 (port 43204) after 10000ms cause=== null
5、Events with Retries and Follow-Ups
OKHttp具有自动重试和重连机制,当连接失败时或者由于url变更发起重定向时,event事件监听会在单个http请求中回掉多次,但是单个http请求的callStart()和callEnd方法只会调用一次
-
流程图如下
-
参考: https://square.github.io/okhttp/events/