Okhttp3 EventListener(二)

2020-05-13  本文已影响0人  coding400
EventListener.png

用途

EventListener 是 OkHttp 用来以上帝视角来对请求指标进行收集,通过实现 EventListener 可以对整个请求请求链路进行埋点监控. 在高并发场景中常用来记录详细的处理耗时日志,进行耗时分析,以便对相应过程进行优化

实现

  1. 实现 EventListener , 因为需要对每个请求都进行监控, 所以需要有一个唯一的标志, 同时还需要这次请求的相关信息 RealCall
@Slf4j
public class HttpEventListener extends EventListener {
  /**
   * 每次请求的标识
   */
  private final long callId;
  /**
   * 每次请求的开始时间,单位毫秒
   */
  private final long callStartMill;
  private StringBuilder sbLog;
  private Call call;
  public HttpEventListener(long callId, Call call) {
    this.callId = callId;
    this.callStartMill = System.currentTimeMillis();
    this.call = call;
    this.sbLog = new StringBuilder(call.request().url().toString()).append(" ").append(callId).append(":");
  }
  private void recordEventLog(String name) {
    long elapseMill = System.currentTimeMillis() - callStartMill;
    sbLog.append(name).append("=").append(elapseMill).append(";");
    if (name.equalsIgnoreCase("callEnd") || name.equalsIgnoreCase("callFailed")) {
      long totalCost = System.currentTimeMillis() - callStartMill;
      //打印出每个步骤的时间点
        log.info(sbLog.toString());
    }
  }
  @Override
  public void callStart(Call call) {
    super.callStart(call);
    recordEventLog("callStart");
  }

  @Override
  public void dnsStart(Call call, String domainName) {
    super.dnsStart(call, domainName);
    recordEventLog("dnsStart");
  }
...... 省略部分
  @Override
  public void callEnd(Call call) {
    super.callEnd(call);
    recordEventLog("callEnd");
  }
}
  1. 实现 EventListener.Factory ,该接口用于为每一次请求创建一个 EventListener 对象
  public static final Factory FACTORY = new Factory() {
    final AtomicLong nextCallId = new AtomicLong(1L);

    @Override
    public EventListener create(Call call) {
      long callId = nextCallId.getAndIncrement();
      return new HttpEventListener(callId, call);
    }
  };
  1. 覆盖默认 Factory
    OkHttpClient httpClient = new OkHttpClient.Builder()
        .callTimeout(500, TimeUnit.MILLISECONDS)
        .connectTimeout(500, TimeUnit.MILLISECONDS)
        //......省略若干
        .eventListenerFactory(HttpEventListener.FACTORY)
        .build();

EventListener 各个事件介绍

  1. callStart(Call call)
    在 http 客户端执行 enqueued or executed 方法时,将首先执行该方法,无论开启了重试都只执行一次
  2. dnsStart(Call call, String domainName)
  3. dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList)
    dnsStart 和 dnsEnd 通常成对出现, 在与远程主机建立连接的时候被会触发,因为重试的原因,所以可能被调用多次
  4. connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy)
  5. connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol)
  6. connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol, IOException ioe)

connectStart 要么与 connectEnd成对出现, 要么与 connectFailed 成对出现. 在启动套接字连接之前调用 connectStart , 连接建立成功之后调用 connectEnd,失败则 connectFailed . 当失败时,如果有更多路由可用并且启用了重试策略, 那么 connectStart 和 connectFailed 可能会出现多次

注意:当复用连接池里的连接时, dnsStart、dnsEnd、 connectStart、connectEnd、connectFailed 均不会被触发

  1. connectionAcquired(Call call, Connection connection)
    当连接已经被获取到时, 该方法将被触发, 如果 call.request() 的响应是重定向到其他地址, 那么该方法将可能被调用多次

  2. connectionReleased(Call call, Connection connection)
    当连接被关闭时, 该方法将被触发, 同 connectionAcquired , 如果 call.request() 的响应是重定向到其他地址, 那么该方法将可能被调用多次

  3. requestHeadersStart(Call call)

  4. requestHeadersEnd(Call call, Request request)

  5. requestBodyStart(Call call)

  6. requestBodyEnd(Call call, long byteCount)

  7. responseHeadersStart(Call call)

  8. responseHeadersEnd(Call call, Response response)

  9. responseBodyStart(Call call)

  10. responseBodyEnd(Call call, long byteCount)

9 - 16 中的方法可能会因为 redirect 和 重试的原因执行多次, 并且都是成对出现

  1. callEnd(Call call)
  2. callFailed(Call call, IOException ioe)
    与 callStart 成对出现, 当出现异常时, callFailed将被触发
上一篇 下一篇

猜你喜欢

热点阅读