這新專案我選擇使用了之前沒使用過的 Jersey Client ~ 由於希望分析打到其他服務的 P99 latency,所以我研究了一下怎麼去 log 下來所有的 duration (如果不知道什麼是 P99 latency 可以參考這篇文章 “What is P99 latency")。這邊分享一下,我最後使用的方法,由於不太熟 Jersey Client,所以最後也是花了一點時間才找到使用 ClientRequestFilter & ClientResponseFilter 來解決。
前置作業
這邊使用 Maven Project 作為範例
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>org.example</groupId>
8 <artifactId>jerseyClient</artifactId>
9 <version>1.0-SNAPSHOT</version>
10
11 <dependencies>
12 <dependency>
13 <groupId>org.projectlombok</groupId>
14 <artifactId>lombok</artifactId>
15 <version>1.18.20</version>
16 <scope>provided</scope>
17 </dependency>
18 <dependency>
19 <groupId>org.glassfish.jersey.core</groupId>
20 <artifactId>jersey-client</artifactId>
21 <version>2.33</version>
22 </dependency>
23 <dependency>
24 <groupId>org.glassfish.jersey.inject</groupId>
25 <artifactId>jersey-hk2</artifactId>
26 <version>2.28</version>
27 </dependency>
28 </dependencies>
29 <properties>
30 <maven.compiler.source>11</maven.compiler.source>
31 <maven.compiler.target>11</maven.compiler.target>
32 </properties>
33
34</project>
1package com.demo;
2
3import javax.ws.rs.client.Client;
4import javax.ws.rs.client.ClientBuilder;
5import javax.ws.rs.client.WebTarget;
6import javax.ws.rs.core.MediaType;
7import java.util.concurrent.TimeUnit;
8
9public class MAIN {
10 public static void main(String[] args) {
11 Client client = ClientBuilder.newBuilder()
12 .connectTimeout(30, TimeUnit.SECONDS)
13 .build();
14 //Filter 在後面的範例中
15 WebTarget webTarget = client.target("https://google.com").register(new Filter());
16 webTarget
17 .request(MediaType.APPLICATION_JSON_TYPE)
18 .get(String.class);
19 }
20}
ClientResponseFilter
實作 Interface javax.ws.rs.client.ClientResponseFilter 可以處理所有的每個 Response 的結果 ~ 可以拿到 ClientRequestContext & ClientRequestContext,以下是範例。
1package com.demo;
2
3import javax.ws.rs.client.ClientRequestContext;
4import javax.ws.rs.client.ClientResponseContext;
5import javax.ws.rs.client.ClientResponseFilter;
6import java.io.IOException;
7
8public class Filter implements ClientResponseFilter {
9 @Override
10 public void filter(ClientRequestContext requestContext,
11 ClientResponseContext responseContext) throws IOException {
12 System.out.println(String.format("requestUri=\"%s\", method=\"%s\", responseStatus=\"%s\", requestTime=\"%s\", responseTime=\"%s\"",
13 requestContext.getUri(),
14 requestContext.getMethod(),
15 responseContext.getStatus(),
16 requestContext.getDate(),
17 responseContext.getDate()));
18 }
19}
這邊可以看到,ClientRequestContext & ClientResponseContext 都有 getDate() 的函式返回一個 java.util.Date!天真的我一開始以為可以靠這兩個 getDate() 算出這個 response 的 duration,但實際執行結果卻出乎我的意料,requestTime 竟然是 null。
1requestUri="https://google.com", method="GET", responseStatus="200", requestTime="null", responseTime="Wed Jun 30 22:41:53 CST 2021"
ClientRequestFilter
當時有點犯蠢,想說 requestTime 是 Null 就差點放棄,不知道怎麼完全沒想到竟然有 ClientResponseFilter ,那怎麼會沒有 ClientRequestFilter 呢!所以這邊最後靠著 ClientRequestFilter ,在每個 request 送出去前,把系統當下時間塞進去 requestContext ,這樣就可以在 response 回來時拉到當初 request 送出時間。
1package com.demo;
2
3import javax.ws.rs.client.ClientRequestContext;
4import javax.ws.rs.client.ClientRequestFilter;
5import javax.ws.rs.client.ClientResponseContext;
6import javax.ws.rs.client.ClientResponseFilter;
7import java.io.IOException;
8
9public class Filter implements ClientResponseFilter, ClientRequestFilter {
10 private static final String REQUEST_TIME = "REQUEST_TIME";
11
12 @Override
13 public void filter(ClientRequestContext requestContext) throws IOException {
14 long currentTimeMillis = System.currentTimeMillis();
15 requestContext.setProperty(REQUEST_TIME, currentTimeMillis);
16 }
17
18 @Override
19 public void filter(ClientRequestContext requestContext,
20 ClientResponseContext responseContext) throws IOException {
21 long requestTime = (Long) requestContext.getProperty(REQUEST_TIME);
22 long currentTimeMillis = System.currentTimeMillis();
23 long duration = currentTimeMillis - requestTime;
24
25 System.out.println(String.format("requestUri=\"%s\", method=\"%s\", responseStatus=\"%s\", duration=\"%d\"",
26 requestContext.getUri(),
27 requestContext.getMethod(),
28 responseContext.getStatus(),
29 duration));
30 }
31}
透過 ClientResponseFilter & ClientRequestFilter 就可以簡單算出每個 request duration ~ 希望有幫助到看到這邊文章的人
評論