Skip to content

Commit 87230a7

Browse files
committed
#41 - ENH: Add HttpClientContext metrics() to provide statistical overview of activity
1 parent b399f7e commit 87230a7

19 files changed

+197
-22
lines changed

client/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<dependency>
3535
<groupId>io.avaje</groupId>
3636
<artifactId>avaje-jsonb</artifactId>
37-
<version>0.11</version>
37+
<version>0.12</version>
3838
<optional>true</optional>
3939
</dependency>
4040

client/src/main/java/io/avaje/http/client/DHttpApi.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/**
1111
* Service loads the HttpApiProvider for HttpApi.
1212
*/
13-
class DHttpApi {
13+
final class DHttpApi {
1414

1515
private static final Logger log = LoggerFactory.getLogger(DHttpApi.class);
1616

client/src/main/java/io/avaje/http/client/DHttpAsync.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import java.util.concurrent.CompletableFuture;
77
import java.util.stream.Stream;
88

9-
class DHttpAsync implements HttpAsyncResponse {
9+
final class DHttpAsync implements HttpAsyncResponse {
1010

1111
private final DHttpClientRequest request;
1212

client/src/main/java/io/avaje/http/client/DHttpCall.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import java.util.concurrent.CompletableFuture;
77
import java.util.stream.Stream;
88

9-
class DHttpCall implements HttpCallResponse {
9+
final class DHttpCall implements HttpCallResponse {
1010

1111
private final DHttpClientRequest request;
1212

client/src/main/java/io/avaje/http/client/DHttpClientContext.java

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
import java.util.Map;
1313
import java.util.concurrent.CompletableFuture;
1414
import java.util.concurrent.atomic.AtomicReference;
15+
import java.util.concurrent.atomic.LongAccumulator;
16+
import java.util.concurrent.atomic.LongAdder;
1517

16-
class DHttpClientContext implements HttpClientContext {
18+
final class DHttpClientContext implements HttpClientContext {
1719

1820
/**
1921
* HTTP Authorization header.
@@ -33,6 +35,12 @@ class DHttpClientContext implements HttpClientContext {
3335
private final AtomicReference<AuthToken> tokenRef = new AtomicReference<>();
3436
private int loggingMaxBody = 1_000;
3537

38+
private final LongAdder metricResTotal = new LongAdder();
39+
private final LongAdder metricResError = new LongAdder();
40+
private final LongAdder metricResBytes = new LongAdder();
41+
private final LongAdder metricResMicros = new LongAdder();
42+
private final LongAccumulator metricResMaxMicros = new LongAccumulator(Math::max, 0);
43+
3644
DHttpClientContext(HttpClient httpClient, String baseUrl, Duration requestTimeout, BodyAdapter bodyAdapter, RetryHandler retryHandler, RequestListener requestListener, AuthTokenProvider authTokenProvider, RequestIntercept intercept) {
3745
this.httpClient = httpClient;
3846
this.baseUrl = baseUrl;
@@ -94,6 +102,76 @@ public HttpClient httpClient() {
94102
return httpClient;
95103
}
96104

105+
@Override
106+
public Metrics metrics() {
107+
return metrics(false);
108+
}
109+
110+
@Override
111+
public Metrics metrics(boolean reset) {
112+
if (reset) {
113+
return new DMetrics(metricResTotal.sumThenReset(), metricResError.sumThenReset(), metricResBytes.sumThenReset(), metricResMicros.sumThenReset(), metricResMaxMicros.getThenReset());
114+
} else {
115+
return new DMetrics(metricResTotal.sum(), metricResError.sum(), metricResBytes.sum(), metricResMicros.sum(), metricResMaxMicros.get());
116+
}
117+
}
118+
119+
void metricsString(int stringBody) {
120+
metricResBytes.add(stringBody);
121+
}
122+
123+
static final class DMetrics implements Metrics {
124+
125+
private final long totalCount;
126+
private final long errorCount;
127+
private final long responseBytes;
128+
private final long totalMicros;
129+
private final long maxMicros;
130+
131+
DMetrics(long totalCount, long errorCount, long responseBytes, long totalMicros, long maxMicros) {
132+
this.totalCount = totalCount;
133+
this.errorCount = errorCount;
134+
this.responseBytes = responseBytes;
135+
this.totalMicros = totalMicros;
136+
this.maxMicros = maxMicros;
137+
}
138+
139+
@Override
140+
public String toString() {
141+
return "totalCount:" + totalCount + " errorCount:" + errorCount + " responseBytes:" + responseBytes + " totalMicros:" + totalMicros + " avgMicros:" + avgMicros()+ " maxMicros:" + maxMicros;
142+
}
143+
144+
@Override
145+
public long totalCount() {
146+
return totalCount;
147+
}
148+
149+
@Override
150+
public long errorCount() {
151+
return errorCount;
152+
}
153+
154+
@Override
155+
public long responseBytes() {
156+
return responseBytes;
157+
}
158+
159+
@Override
160+
public long totalMicros() {
161+
return totalMicros;
162+
}
163+
164+
@Override
165+
public long maxMicros() {
166+
return maxMicros;
167+
}
168+
169+
@Override
170+
public long avgMicros() {
171+
return totalCount == 0 ? 0 : totalMicros / totalCount;
172+
}
173+
}
174+
97175
@Override
98176
public void checkResponse(HttpResponse<?> response) {
99177
if (response.statusCode() >= 300) {
@@ -123,6 +201,10 @@ public BodyContent readErrorContent(boolean responseAsBytes, HttpResponse<?> htt
123201

124202
@Override
125203
public BodyContent readContent(HttpResponse<byte[]> httpResponse) {
204+
final byte[] body = httpResponse.body();
205+
if (body != null && body.length > 0) {
206+
metricResBytes.add(body.length);
207+
}
126208
byte[] bodyBytes = decodeContent(httpResponse);
127209
final String contentType = getContentType(httpResponse);
128210
return new BodyContent(contentType, bodyBytes);
@@ -193,6 +275,12 @@ <T> List<T> readList(Class<T> cls, BodyContent content) {
193275
}
194276

195277
void afterResponse(DHttpClientRequest request) {
278+
metricResTotal.add(1);
279+
metricResMicros.add(request.responseTimeMicros());
280+
metricResMaxMicros.accumulate(request.responseTimeMicros());
281+
if (request.response().statusCode() >= 300) {
282+
metricResError.add(1);
283+
}
196284
if (requestListener != null) {
197285
requestListener.response(request.listenerEvent());
198286
}

client/src/main/java/io/avaje/http/client/DHttpClientContextBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import static java.util.Objects.requireNonNull;
1616

17-
class DHttpClientContextBuilder implements HttpClientContext.Builder {
17+
final class DHttpClientContextBuilder implements HttpClientContext.Builder {
1818

1919
private HttpClient client;
2020
private String baseUrl;

client/src/main/java/io/avaje/http/client/DHttpClientRequest.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -531,16 +531,21 @@ public HttpResponse<byte[]> asByteArray() {
531531
return withHandler(HttpResponse.BodyHandlers.ofByteArray());
532532
}
533533

534+
private HttpResponse<String> addMetrics(final HttpResponse<String> res) {
535+
context.metricsString(res.body().length());
536+
return res;
537+
}
538+
534539
@Override
535540
public HttpResponse<String> asString() {
536541
loggableResponseBody = true;
537-
return withHandler(HttpResponse.BodyHandlers.ofString());
542+
return addMetrics(withHandler(HttpResponse.BodyHandlers.ofString()));
538543
}
539544

540545
@Override
541546
public HttpResponse<String> asPlainString() {
542547
loggableResponseBody = true;
543-
final HttpResponse<String> hres = withHandler(HttpResponse.BodyHandlers.ofString());
548+
final HttpResponse<String> hres = addMetrics(withHandler(HttpResponse.BodyHandlers.ofString()));
544549
context.checkResponse(hres);
545550
return hres;
546551
}

client/src/main/java/io/avaje/http/client/DHttpClientRequestWithRetry.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/**
77
* Extends DHttpClientRequest with retry attempts.
88
*/
9-
class DHttpClientRequestWithRetry extends DHttpClientRequest {
9+
final class DHttpClientRequestWithRetry extends DHttpClientRequest {
1010

1111
private final RetryHandler retryHandler;
1212
private int retryCount;

client/src/main/java/io/avaje/http/client/DRequestInterceptors.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* <p>
1111
* Noting that afterResponse interceptors are processed in reverse order.
1212
*/
13-
class DRequestInterceptors implements RequestIntercept {
13+
final class DRequestInterceptors implements RequestIntercept {
1414

1515
private final List<RequestIntercept> before;
1616
private final List<RequestIntercept> after;

client/src/main/java/io/avaje/http/client/DRequestListeners.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import java.util.List;
44

5-
class DRequestListeners implements RequestListener {
5+
final class DRequestListeners implements RequestListener {
66

77
private final RequestListener[] listeners;
88

0 commit comments

Comments
 (0)