Event

Events allow you to capture metrics on your application’s HTTP calls. Use events to monitor: The size and frequency of the HTTP calls your application makes. If you’re making too many calls, or your calls are too large, you should know about it! The performance of these calls on the underlying network. If the network’s performance isn’t sufficient, you need to either improve the network or use less of it.

Events允许你捕获你的应用Http请求的调用监控(也就是生命周期)。 使用Events可以展示:
.应用Http请求发出的大小和频率, 如果你发出了太多请求, 或者你的请求太大, 你应该了解它。
.底层网络调用的性能。如果性能不足, 你应该提高网络或减少网络使用。

EventListener

Subclass EventListener and override methods for the events you are interested in. In a successful HTTP call with no redirects or retries the sequence of events is described by this flow.

继承EventListener, 重写你感兴趣的events方法。 在一次没有重定向 或 重试的Http成功请求中, 事件序列执行如下。

Here’s a sample event listener that prints each event with a timestamp.

这是一个打印每个事件的简单的eventListener。

class PrintingEventListener extends EventListener {private long callStartNanos;private void printEvent(String name) {long nowNanos = System.nanoTime();if (name.equals("callStart")) {callStartNanos = nowNanos;}long elapsedNanos = nowNanos - callStartNanos;System.out.printf("%.3f %s%n", elapsedNanos / 1000000000d, name);}@Override public void callStart(Call call) {printEvent("callStart");}@Override public void callEnd(Call call) {printEvent("callEnd");}@Override public void dnsStart(Call call, String domainName) {printEvent("dnsStart");}@Override public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {printEvent("dnsEnd");}...
}
复制代码

我们发几个请求:

Request request = new Request.Builder().url("https://publicobject.com/helloworld.txt").build();System.out.println("REQUEST 1 (new connection)");
try (Response response = client.newCall(request).execute()) {// Consume and discard the response body.response.body().source().readByteString();
}System.out.println("REQUEST 2 (pooled connection)");
try (Response response = client.newCall(request).execute()) {// Consume and discard the response body.response.body().source().readByteString();
}
复制代码

EventListener会打印相应的事件:

REQUEST 1 (new connection)
0.000 callStart
0.010 dnsStart
0.017 dnsEnd
0.025 connectStart
0.117 secureConnectStart
0.586 secureConnectEnd
0.586 connectEnd
0.587 connectionAcquired
0.588 requestHeadersStart
0.590 requestHeadersEnd
0.591 responseHeadersStart
0.675 responseHeadersEnd
0.676 responseBodyStart
0.679 responseBodyEnd
0.679 connectionReleased
0.680 callEnd
REQUEST 2 (pooled connection)
0.000 callStart
0.001 connectionAcquired
0.001 requestHeadersStart
0.001 requestHeadersEnd
0.002 responseHeadersStart
0.082 responseHeadersEnd
0.082 responseBodyStart
0.082 responseBodyEnd
0.083 connectionReleased
0.083 callEnd
复制代码

Notice how no connect events are fired for the second call. It reused the connection from the first request for dramatically better performance.

注意: 第二次调用没有触发连接事件。 它重用了第一次连接, 从而显著提高了性能。

EventListener。Factory

In the preceding example we used a field, callStartNanos, to track the elapsed time of each event. This is handy, but it won’t work if multiple calls are executing concurrently. To accommodate this, use a Factory to create a new EventListener instance for each Call. This allows each listener to keep call-specific state. This sample factory creates a unique ID for each call and uses that ID to differentiate calls in log messages.

在前面的示例中,我们使用了一个字段callStartNanos来跟踪每个事件的已用时间。这很方便,但如果多个调用同时执行,它将无法工作。 为了适应这种情况,请使用Factory为每个Call创建一个新的EventListener实例。 这允许每个监听器保持特定于呼叫的状态。 此示例工厂为每个调用创建唯一ID,并使用该ID区分日志消息中的调用。

class PrintingEventListener extends EventListener {public static final Factory FACTORY = new Factory() {final AtomicLong nextCallId = new AtomicLong(1L);@Override public EventListener create(Call call) {long callId = nextCallId.getAndIncrement();System.out.printf("%04d %s%n", callId, call.request().url());return new PrintingEventListener(callId, System.nanoTime());}};final long callId;final long callStartNanos;public PrintingEventListener(long callId, long callStartNanos) {this.callId = callId;this.callStartNanos = callStartNanos;}private void printEvent(String name) {long elapsedNanos = System.nanoTime() - callStartNanos;System.out.printf("%04d %.3f %s%n", callId, elapsedNanos / 1000000000d, name);}@Override public void callStart(Call call) {printEvent("callStart");}@Override public void callEnd(Call call) {printEvent("callEnd");}...
}
复制代码

We can use this listener to race a pair of concurrent HTTP requests

我们可以使用这个listener来同时追踪一对HTTP请求:

Request washingtonPostRequest = new Request.Builder().url("https://www.washingtonpost.com/").build();
client.newCall(washingtonPostRequest).enqueue(new Callback() {...
});Request newYorkTimesRequest = new Request.Builder().url("https://www.nytimes.com/").build();
client.newCall(newYorkTimesRequest).enqueue(new Callback() {...
});
复制代码

Running this race over home WiFi shows the Times (0002) completes just slightly sooner than the Post (0001):

在WiFi上运行这次追踪显示, 0002的完成时间只比0001快一点。

0001 https://www.washingtonpost.com/
0001 0.000 callStart
0002 https://www.nytimes.com/
0002 0.000 callStart
0002 0.010 dnsStart
0001 0.013 dnsStart
0001 0.022 dnsEnd
0002 0.019 dnsEnd
0001 0.028 connectStart
0002 0.025 connectStart
0002 0.072 secureConnectStart
0001 0.075 secureConnectStart
0001 0.386 secureConnectEnd
0002 0.390 secureConnectEnd
0002 0.400 connectEnd
0001 0.403 connectEnd
0002 0.401 connectionAcquired
0001 0.404 connectionAcquired
0001 0.406 requestHeadersStart
0002 0.403 requestHeadersStart
0001 0.414 requestHeadersEnd
0002 0.411 requestHeadersEnd
0002 0.412 responseHeadersStart
0001 0.415 responseHeadersStart
0002 0.474 responseHeadersEnd
0002 0.475 responseBodyStart
0001 0.554 responseHeadersEnd
0001 0.555 responseBodyStart
0002 0.554 responseBodyEnd
0002 0.554 connectionReleased
0002 0.554 callEnd
0001 0.624 responseBodyEnd
0001 0.624 connectionReleased
0001 0.624 callEnd
复制代码

The EventListener.Factory also makes it possible to limit metrics to a subset of calls. This one captures metrics on a random 10%:

EventListener.Factory还可以限制一部分请求的指标。 这个随机捕获10%的指标:

class MetricsEventListener extends EventListener {private static final Factory FACTORY = new Factory() {@Override public EventListener create(Call call) {if (Math.random() < 0.10) {return new MetricsEventListener(call);} else {return EventListener.NONE;}}};...
}
复制代码

Events with Failures(有失败的事件)

When an operation fails, a failure method is called. This is connectFailed() for failures while building a connection to the server, and callFailed() when the HTTP call fails permanently. When a failure happens it is possible that a start event won’t have a corresponding end event.

当一个操作失败了, 失败的方法会被调用。 这是一个在创建服务器连接时的连接错误。 当失败发生时, 可能一个开始事件就不会有对应的结束事件了。

Events with Retries and Follow-Ups(带重试的事件和跟进)

OkHttp is resilient and can automatically recover from some connectivity failures. In this case, the connectFailed() event is not terminal and not followed by callFailed(). Event listeners will receive multiple events of the same type when retries are attempted. A single HTTP call may require follow-up requests to be made to handle authentication challenges, redirects, and HTTP-layer timeouts. In such cases multiple connections, requests, and responses may be attempted. Follow-ups are another reason a single call may trigger multiple events of the same type.

OkHttp具有弹性, 可以自动从连接故障中恢复。 这种情况下, connectFailed()不是终点, 且后面没有callFailed()。 在尝试重试时, EventListener将会接收多个同类型的事件。
单个请求调用可能需要后序的请求来询问身份验证, 重定向, 和Http层面的超时。 在这种情况下, 多个连接请求和响应会发生。后序请求是可能会收到多个同类型事件的原因。

适用性

事件机制可以在OkHttp 3.11版本公开使用。 未来可能会引入新的事件类型, 你需要重写响应的方法来处理。

深入剖析OkHttp系列(五) 来自官方的事件机制相关推荐

  1. 深入剖析Redis系列(五) - Redis数据结构之字符串

    前言 字符串类型 是 Redis 最基础的数据结构.字符串类型 的值实际可以是 字符串(简单 和 复杂 的字符串,例如 JSON.XML).数字(整数.浮点数),甚至是 二进制(图片.音频.视频),但 ...

  2. asyncio 系列五、asyncio的事件循环

    官网连接:https://docs.python.org/zh-cn/3.7/library/asyncio-eventloop.html#asyncio.loop.run_in_executor 事 ...

  3. 深入剖析Redis系列(三) - Redis集群模式搭建与原理详解

    前言 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...

  4. 深入剖析Redis系列(七) - Redis数据结构之列表

    前言 列表(list)类型是用来存储多个 有序 的 字符串.在 Redis 中,可以对列表的 两端 进行 插入(push)和 弹出(pop)操作,还可以获取 指定范围 的 元素列表.获取 指定索引下标 ...

  5. python解复杂方程_Python数据处理篇之Sympy系列(五)---解方程

    前言 sympy不仅在符号运算方面强大,在解方程方面也是很强大. 本章节学习对应官网的:Solvers 官方教程 (一)求解多元一次方程-solve() 1.说明: 解多元一次方程可以使用solve( ...

  6. 数据库分库分表(sharding)系列(五) 一种支持自由规划无须数据迁移和修改路由代码的Sharding扩容方案...

    为什么80%的码农都做不了架构师?>>>    版权声明:本文由本人撰写并发表于2012年9月份的<程序员>杂志,原文题目<一种支持自由规划的Sharding扩容方 ...

  7. python 解方程 sympy_Python数据处理篇之Sympy系列(五)---解方程

    前言 sympy不仅在符号运算方面强大,在解方程方面也是很强大. 本章节学习对应官网的:Solvers 官方教程 (一)求解多元一次方程-solve() 1.说明: 解多元一次方程可以使用solve( ...

  8. 慢牛系列五:用百度语音识别添加自选股

    慢牛系列五:用百度语音识别添加自选股 开发慢牛股票app已经有很长一段时间,最近在考虑用什么方式添加自选股最方便?传统的做法是为用户专门开发一个键盘,字母或者数字的,帮助用户录入股票的简称或者编码,大 ...

  9. WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用

    如果一个类型,不一定是数据契约,和给定的数据契约具有很大的差异,而我们要将该类型的对象序列化成基于数据契约对应的XML.反之,对于一段给定的基于数据契约的XML,要通过反序列化生成该类型的对象,我们该 ...

最新文章

  1. blob html 预览_Blob | HTML 5 API | JavaScript 权威指南
  2. python所有软件都打不开机怎么办_电脑软件,小编教你电脑所有软件都打不开怎么解决...
  3. 2.4-2.5、Hive整合(整合Spark、整合Hbase)、连接方式Cli、HiveServer和hivemetastore、Squirrel SQL Client等
  4. 《剑指offer》变态跳台阶
  5. 数学建模算法:支持向量机_从零开始的算法:支持向量机
  6. python打开串口失败_python 如何防止串口通信失败?
  7. SQL性能优化(转)
  8. 【数据结构】——构建二叉树,遍历二叉树
  9. 一步一步学Silverlight 2系列(5):实现简单的拖放功能_转载
  10. 64位CentOS源码编译方式安装wine
  11. h3c配置snmp配置命令_配置单元命令
  12. 拓端tecdat|R语言高维数据的主成分pca、 t-SNE算法降维与可视化分析案例报告
  13. WKWebView终极指南
  14. 不混淆 android jni,JNI 防混淆 Android proguard
  15. u盘文件删除如何恢复呢?
  16. AndroidStudio 集成 OpenCV
  17. 最新版养猫小程序前端+后端搭建详细教程
  18. 局域网搭建IOS应用在线安装环境
  19. 读书笔记--《软技能-代码之外的生存指南》
  20. 猿创征文|『编程与创作』10款颜值颇高的宝藏工具

热门文章

  1. java final关键字_终于明白 Java 为什么要加 final 关键字了!
  2. 手机屏大字滚动_在iPhone手机中,实现长截图的几种方法
  3. StringUtil中常用的方法
  4. common pool2 mysql_用common-pool自定义资源池
  5. 鸢尾花分类_机器学习:鸢尾花数据集--贝叶斯分类
  6. oracle 48小时内_恭喜詹姆斯!恭喜湖人!戴维斯续约最新动态:48小时内或达成...
  7. Linux脚本之定时清空文件内容
  8. NIO详解(四):NIO编程
  9. LetCode: 5. 最长回文子串
  10. Windows下安装Redis及使用Python操作Redis的方法