OkHttp Interceptor日志上报
最近为了做一些网络上的优化,所以就得提前埋点,为后续网络优化提供数据支持。
主要是对发起请求埋点,请求错误埋点,客户端请求耗时埋点。
事件上报到阿里云,接入的是阿里的应用实时监控服务。
网络请求使用的是OhHttp + Retrofit ,现在很多都是这么实现的了吧。
网络的埋点切入口,很容易就想到了 Interceptor,用起来了才觉得 Interceptor 是真的香,以前还只是觉得这个设计模式是真好。用到了才感觉是太香了。
上代码:
class ReportingInterceptor(val source: ACRSource) : Interceptor {
private val gson = Gson()
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val url = request.url.toString()
AlibabaCloudRumUtil.requestStart(source, snapshots = url)
val startTime = System.currentTimeMillis()
val response = chain.proceed(request)
AlibabaCloudRumUtil.requestCost(
source,
snapshots = url,
System.currentTimeMillis() - startTime
)
// 判断是否是 HTTP 错误
if (!response.isSuccessful) {
AlibabaCloudRumUtil.requestFail(
source,
snapshots = url,
params = AlibabaCloudRumUtil.errorMap(
response.code.toString(),
response.message
)
)
} else {
val source = response.body?.source()
source?.request(Long.MAX_VALUE)
try {
val buffer = source?.buffer
// 业务错误逻辑上报
val result = gson.fromJson(
buffer?.clone()?.readString(Charset.forName("UTF-8")),
BaseModel::class.java
)
if (result?.code != 0) {
AlibabaCloudRumUtil.requestFail(
ACRSource.COROUTINE,
snapshots = url,
params = ResultException(
"${result.code}",
result?.message ?: "Unknown error"
).toMap()
)
}
} catch (ex: Exception) {
AlibabaCloudRumUtil.requestFail(
ACRSource.COROUTINE,
snapshots = url,
params = BusinessException.handlerException(ex).toMap()
)
} finally {
source?.close()
}
}
return response
}
}
网络请求上报是带上了URL,现在的Retrofit 的URL 在其他地方是真的不好拿,这 Interceptor 确实方便的很。
而网络耗时也比较容易,在
val response = chain.proceed(request)
前后记录时间就可以了,虽然跟抓包数据显示的网络耗时有差距,但是我们毕竟只是粗略的统计而已。
错误上报的话,包括了 http 请求错误和 code != 0 的业务数据错误,都是需要上报的。
如果需要在其他地方拿到 URL ,需要在 Interceptor 里处理,重新 new 一个 Response 返回,然后把 URL 塞到 Header 里面,在其他地方把 Header 中的 URL 读取出来。但是会产生一点性能开销,毕竟每个请求都需要 new 一个新的 Response 。