Skip to content

Commit

Permalink
Add instrumentation for apache htto components async client pools (co…
Browse files Browse the repository at this point in the history
…mbine both apache httpcomponents binders)
  • Loading branch information
worldtiki authored and shakuzen committed Jan 3, 2020
1 parent 968709c commit 0f0d4fb
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 252 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,49 +15,52 @@
*/
package io.micrometer.core.instrument.binder.httpcomponents;

import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.lang.NonNull;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.pool.ConnPoolControl;

/**
* Collects metrics from a {@link PoolingHttpClientConnectionManager}.
*
* Collects metrics from a {@link ConnPoolControl}, for example a {@link org.apache.http.impl.conn.PoolingHttpClientConnectionManager}.
* <p>
* It monitors the overall connection pool state.
*
* @author Benjamin Hubert (benjamin.hubert@willhaben.at)
* @since 1.3.0
*/
public class PoolingHttpClientConnectionManagerMetricsBinder implements MeterBinder {

private final PoolingHttpClientConnectionManager connectionManager;
private final ConnPoolControl<HttpRoute> connPoolControl;
private final Iterable<Tag> tags;

/**
* Creates a metrics binder for the given pooling connection manager.
* Creates a metrics binder for the given pooling connection pool control.
*
* @param connectionManager The connection manager to monitor.
* @param name Name of the connection manager. Will be added as tag with the
* key "httpclient".
* @param tags Tags to apply to all recorded metrics. Must be an even number
* of arguments representing key/value pairs of tags.
* @param connPoolControl The connection pool control to monitor.
* @param name Name of the connection pool control. Will be added as tag with the
* key "httpclient".
* @param tags Tags to apply to all recorded metrics. Must be an even number
* of arguments representing key/value pairs of tags.
*/
@SuppressWarnings("WeakerAccess")
public PoolingHttpClientConnectionManagerMetricsBinder(PoolingHttpClientConnectionManager connectionManager, String name, String... tags) {
this(connectionManager, name, Tags.of(tags));
public PoolingHttpClientConnectionManagerMetricsBinder(ConnPoolControl<HttpRoute> connPoolControl, String name, String... tags) {
this(connPoolControl, name, Tags.of(tags));
}

/**
* Creates a metrics binder for the given pooling connection manager.
* Creates a metrics binder for the given connection pool control.
*
* @param connectionManager The connection manager to monitor.
* @param name Name of the connection manager. Will be added as tag with the
* key "httpclient".
* @param tags Tags to apply to all recorded metrics.
* @param connPoolControl The connection pool control to monitor.
* @param name Name of the connection pool control. Will be added as tag with the key "httpclient".
* @param tags Tags to apply to all recorded metrics.
*/
@SuppressWarnings("WeakerAccess")
public PoolingHttpClientConnectionManagerMetricsBinder(PoolingHttpClientConnectionManager connectionManager, String name, Iterable<Tag> tags) {
this.connectionManager = connectionManager;
public PoolingHttpClientConnectionManagerMetricsBinder(ConnPoolControl<HttpRoute> connPoolControl, String name, Iterable<Tag> tags) {
this.connPoolControl = connPoolControl;
this.tags = Tags.concat(tags, "httpclient", name);
}

Expand All @@ -68,35 +71,35 @@ public void bindTo(@NonNull MeterRegistry registry) {

private void registerTotalMetrics(MeterRegistry registry) {
Gauge.builder("httpcomponents.httpclient.pool.total.max",
connectionManager,
(connectionManager) -> connectionManager.getTotalStats().getMax())
.description("The configured maximum number of allowed persistent connections for all routes.")
.tags(tags)
.register(registry);
connPoolControl,
(connPoolControl) -> connPoolControl.getTotalStats().getMax())
.description("The configured maximum number of allowed persistent connections for all routes.")
.tags(tags)
.register(registry);
Gauge.builder("httpcomponents.httpclient.pool.total.connections",
connectionManager,
(connectionManager) -> connectionManager.getTotalStats().getAvailable())
.description("The number of persistent and available connections for all routes.")
.tags(tags).tag("state", "available")
.register(registry);
connPoolControl,
(connPoolControl) -> connPoolControl.getTotalStats().getAvailable())
.description("The number of persistent and available connections for all routes.")
.tags(tags).tag("state", "available")
.register(registry);
Gauge.builder("httpcomponents.httpclient.pool.total.connections",
connectionManager,
(connectionManager) -> connectionManager.getTotalStats().getLeased())
.description("The number of persistent and leased connections for all routes.")
.tags(tags).tag("state", "leased")
.register(registry);
connPoolControl,
(connPoolControl) -> connPoolControl.getTotalStats().getLeased())
.description("The number of persistent and leased connections for all routes.")
.tags(tags).tag("state", "leased")
.register(registry);
Gauge.builder("httpcomponents.httpclient.pool.total.pending",
connectionManager,
(connectionManager) -> connectionManager.getTotalStats().getPending())
.description("The number of connection requests being blocked awaiting a free connection for all routes.")
.tags(tags)
.register(registry);
connPoolControl,
(connPoolControl) -> connPoolControl.getTotalStats().getPending())
.description("The number of connection requests being blocked awaiting a free connection for all routes.")
.tags(tags)
.register(registry);
Gauge.builder("httpcomponents.httpclient.pool.route.max.default",
connectionManager,
PoolingHttpClientConnectionManager::getDefaultMaxPerRoute)
.description("The configured default maximum number of allowed persistent connections per route.")
.tags(tags)
.register(registry);
connPoolControl,
ConnPoolControl::getDefaultMaxPerRoute)
.description("The configured default maximum number of allowed persistent connections per route.")
.tags(tags)
.register(registry);
}

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import io.micrometer.core.instrument.MockClock;
import io.micrometer.core.instrument.simple.SimpleConfig;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.ConnPoolControl;
import org.apache.http.pool.PoolStats;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -36,21 +36,21 @@
class PoolingHttpClientConnectionManagerMetricsBinderTest {

private MeterRegistry registry = new SimpleMeterRegistry(SimpleConfig.DEFAULT, new MockClock());
private PoolingHttpClientConnectionManager connectionManager;
private ConnPoolControl connPoolControl;
private PoolingHttpClientConnectionManagerMetricsBinder binder;

@BeforeEach
void setup() {
connectionManager = mock(PoolingHttpClientConnectionManager.class);
binder = new PoolingHttpClientConnectionManagerMetricsBinder(connectionManager, "test");
connPoolControl = mock(ConnPoolControl.class);
binder = new PoolingHttpClientConnectionManagerMetricsBinder(connPoolControl, "test");
binder.bindTo(registry);
}

@Test
void totalMax() {
PoolStats poolStats = mock(PoolStats.class);
when(poolStats.getMax()).thenReturn(13);
when(connectionManager.getTotalStats()).thenReturn(poolStats);
when(connPoolControl.getTotalStats()).thenReturn(poolStats);
assertThat(registry.get("httpcomponents.httpclient.pool.total.max")
.tags("httpclient", "test")
.gauge().value()).isEqualTo(13.0);
Expand All @@ -60,7 +60,7 @@ void totalMax() {
void totalAvailable() {
PoolStats poolStats = mock(PoolStats.class);
when(poolStats.getAvailable()).thenReturn(17);
when(connectionManager.getTotalStats()).thenReturn(poolStats);
when(connPoolControl.getTotalStats()).thenReturn(poolStats);
assertThat(registry.get("httpcomponents.httpclient.pool.total.connections")
.tags("httpclient", "test", "state", "available")
.gauge().value()).isEqualTo(17.0);
Expand All @@ -70,7 +70,7 @@ void totalAvailable() {
void totalLeased() {
PoolStats poolStats = mock(PoolStats.class);
when(poolStats.getLeased()).thenReturn(23);
when(connectionManager.getTotalStats()).thenReturn(poolStats);
when(connPoolControl.getTotalStats()).thenReturn(poolStats);
assertThat(registry.get("httpcomponents.httpclient.pool.total.connections")
.tags("httpclient", "test", "state", "leased")
.gauge().value()).isEqualTo(23.0);
Expand All @@ -80,15 +80,15 @@ void totalLeased() {
void totalPending() {
PoolStats poolStats = mock(PoolStats.class);
when(poolStats.getPending()).thenReturn(37);
when(connectionManager.getTotalStats()).thenReturn(poolStats);
when(connPoolControl.getTotalStats()).thenReturn(poolStats);
assertThat(registry.get("httpcomponents.httpclient.pool.total.pending")
.tags("httpclient", "test")
.gauge().value()).isEqualTo(37.0);
}

@Test
void routeMaxDefault() {
when(connectionManager.getDefaultMaxPerRoute()).thenReturn(7);
when(connPoolControl.getDefaultMaxPerRoute()).thenReturn(7);
assertThat(registry.get("httpcomponents.httpclient.pool.route.max.default")
.tags("httpclient", "test")
.gauge().value()).isEqualTo(7.0);
Expand Down
Loading

0 comments on commit 0f0d4fb

Please sign in to comment.