Skip to content

Commit d3ecef9

Browse files
committed
Initial metrics implementation in client v2 using micrometer
1 parent 7a15ecb commit d3ecef9

File tree

5 files changed

+99
-10
lines changed

5 files changed

+99
-10
lines changed

client-v2/pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@
7474
<artifactId>jackson-core</artifactId>
7575
<version>2.17.2</version>
7676
</dependency>
77+
<dependency>
78+
<groupId>io.micrometer</groupId>
79+
<artifactId>micrometer-core</artifactId>
80+
<version>1.14.3</version>
81+
</dependency>
82+
7783

7884
<!-- Test Dependencies -->
7985
<dependency>
@@ -135,6 +141,13 @@
135141
<scope>test</scope>
136142
</dependency>
137143

144+
<!-- https://mvnrepository.com/artifact/io.micrometer/micrometer-observation -->
145+
<dependency>
146+
<groupId>io.micrometer</groupId>
147+
<artifactId>micrometer-observation</artifactId>
148+
<version>1.14.3</version>
149+
<scope>test</scope>
150+
</dependency>
138151
</dependencies>
139152

140153
<build>

client-v2/src/main/java/com/clickhouse/client/api/Client.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.clickhouse.client.config.ClickHouseClientOption;
4646
import com.clickhouse.data.ClickHouseColumn;
4747
import com.clickhouse.data.ClickHouseFormat;
48+
import io.micrometer.core.instrument.MeterRegistry;
4849
import org.apache.hc.client5.http.ConnectTimeoutException;
4950
import org.apache.hc.core5.concurrent.DefaultThreadFactory;
5051
import org.apache.hc.core5.http.ClassicHttpResponse;
@@ -158,15 +159,22 @@ public class Client implements AutoCloseable {
158159

159160
// Server context
160161
private String serverVersion;
162+
private Object metrics;
161163

162164
private Client(Set<String> endpoints, Map<String,String> configuration, boolean useNewImplementation,
163165
ExecutorService sharedOperationExecutor, ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy) {
166+
this(endpoints, configuration, useNewImplementation, sharedOperationExecutor, columnToMethodMatchingStrategy, null);
167+
}
168+
169+
private Client(Set<String> endpoints, Map<String,String> configuration, boolean useNewImplementation,
170+
ExecutorService sharedOperationExecutor, ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy, Object metrics) {
164171
this.endpoints = endpoints;
165172
this.configuration = configuration;
166173
this.readOnlyConfig = Collections.unmodifiableMap(this.configuration);
167174
this.endpoints.forEach(endpoint -> {
168175
this.serverNodes.add(ClickHouseNode.of(endpoint, this.configuration));
169176
});
177+
this.metrics = metrics;
170178
this.serializers = new ConcurrentHashMap<>();
171179
this.deserializers = new ConcurrentHashMap<>();
172180

@@ -178,15 +186,13 @@ private Client(Set<String> endpoints, Map<String,String> configuration, boolean
178186
}
179187
this.useNewImplementation = useNewImplementation;
180188
if (useNewImplementation) {
181-
this.httpClientHelper = new HttpAPIClientHelper(configuration);
189+
this.httpClientHelper = new HttpAPIClientHelper(configuration, metrics);
182190
LOG.info("Using new http client implementation");
183191
} else {
184192
this.oldClient = ClientV1AdaptorHelper.createClient(configuration);
185193
LOG.info("Using old http client implementation");
186194
}
187195
this.columnToMethodMatchingStrategy = columnToMethodMatchingStrategy;
188-
189-
190196
updateServerContext();
191197
}
192198

@@ -252,7 +258,7 @@ public static class Builder {
252258

253259
private ExecutorService sharedOperationExecutor = null;
254260
private ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy;
255-
261+
private Object metric = null;
256262
public Builder() {
257263
this.endpoints = new HashSet<>();
258264
this.configuration = new HashMap<String, String>();
@@ -967,6 +973,15 @@ public Builder useBearerTokenAuth(String bearerToken) {
967973
this.httpHeader(HttpHeaders.AUTHORIZATION, "Bearer " + bearerToken);
968974
return this;
969975
}
976+
public Builder addMetric(Object metric, String name) {
977+
if (metric instanceof MeterRegistry) {
978+
this.metric = metric;
979+
this.configuration.put(ClientConfigProperties.METRICS_NAME.getKey(), name);
980+
} else {
981+
throw new IllegalArgumentException("Unsupported metric type. Only MeterRegistry is supported");
982+
}
983+
return this;
984+
}
970985

971986
public Client build() {
972987
setDefaults();
@@ -1027,7 +1042,7 @@ public Client build() {
10271042
}
10281043

10291044
return new Client(this.endpoints, this.configuration, this.useNewImplementation, this.sharedOperationExecutor,
1030-
this.columnToMethodMatchingStrategy);
1045+
this.columnToMethodMatchingStrategy, this.metric);
10311046
}
10321047

10331048

client-v2/src/main/java/com/clickhouse/client/api/ClientConfigProperties.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,10 @@ public enum ClientConfigProperties {
127127
* Indicates that data provided for write operation is compressed by application.
128128
*/
129129
APP_COMPRESSED_DATA("app_compressed_data"),
130-
130+
/**
131+
*
132+
*/
133+
METRICS_NAME("metrics_name"),
131134
;
132135

133136
private String key;

client-v2/src/main/java/com/clickhouse/client/api/internal/HttpAPIClientHelper.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import com.clickhouse.client.api.data_formats.internal.SerializerUtils;
1414
import com.clickhouse.client.api.enums.ProxyType;
1515
import com.clickhouse.client.api.http.ClickHouseHttpProto;
16+
import io.micrometer.core.instrument.MeterRegistry;
17+
import io.micrometer.core.instrument.binder.httpcomponents.hc5.PoolingHttpClientConnectionManagerMetricsBinder;
1618
import org.apache.hc.client5.http.ConnectTimeoutException;
1719
import org.apache.hc.client5.http.classic.methods.HttpPost;
1820
import org.apache.hc.client5.http.config.ConnectionConfig;
@@ -21,6 +23,7 @@
2123
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
2224
import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager;
2325
import org.apache.hc.client5.http.impl.io.ManagedHttpClientConnectionFactory;
26+
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
2427
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
2528
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
2629
import org.apache.hc.client5.http.protocol.HttpClientContext;
@@ -92,9 +95,10 @@ public class HttpAPIClientHelper {
9295
private final Set<ClientFaultCause> defaultRetryCauses;
9396

9497
private String defaultUserAgent;
95-
96-
public HttpAPIClientHelper(Map<String, String> configuration) {
98+
private Object metric;
99+
public HttpAPIClientHelper(Map<String, String> configuration, Object metric) {
97100
this.chConfiguration = configuration;
101+
this.metric = metric;
98102
this.httpClient = createHttpClient();
99103

100104
RequestConfig.Builder reqConfBuilder = RequestConfig.custom();
@@ -187,7 +191,6 @@ private HttpClientConnectionManager poolConnectionManager(SSLContext sslContext,
187191
PoolingHttpClientConnectionManagerBuilder connMgrBuilder = PoolingHttpClientConnectionManagerBuilder.create()
188192
.setPoolConcurrencyPolicy(PoolConcurrencyPolicy.LAX);
189193

190-
191194
ConnectionReuseStrategy connectionReuseStrategy =
192195
ConnectionReuseStrategy.valueOf(chConfiguration.get("connection_reuse_strategy"));
193196
switch (connectionReuseStrategy) {
@@ -219,7 +222,12 @@ private HttpClientConnectionManager poolConnectionManager(SSLContext sslContext,
219222
connMgrBuilder.setConnectionFactory(connectionFactory);
220223
connMgrBuilder.setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext));
221224
connMgrBuilder.setDefaultSocketConfig(socketConfig);
222-
return connMgrBuilder.build();
225+
PoolingHttpClientConnectionManager phccm = connMgrBuilder.build();
226+
if (metric != null && metric instanceof MeterRegistry) {
227+
String name = chConfiguration.getOrDefault(ClientConfigProperties.METRICS_NAME.getKey(), "http-pool");
228+
new PoolingHttpClientConnectionManagerMetricsBinder(phccm, name).bindTo((MeterRegistry) metric);
229+
}
230+
return phccm;
223231
}
224232

225233
public CloseableHttpClient createHttpClient() {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.clickhouse.client.metrics;
2+
3+
import com.clickhouse.client.BaseIntegrationTest;
4+
import com.clickhouse.client.ClickHouseNode;
5+
import com.clickhouse.client.ClickHouseProtocol;
6+
import com.clickhouse.client.ClickHouseServerForTest;
7+
import com.clickhouse.client.api.Client;
8+
import com.clickhouse.client.api.enums.Protocol;
9+
import com.clickhouse.client.api.internal.ServerSettings;
10+
import io.micrometer.core.instrument.MeterRegistry;
11+
import io.micrometer.core.instrument.Metrics;
12+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
13+
import org.testng.annotations.AfterMethod;
14+
import org.testng.annotations.BeforeMethod;
15+
import org.testng.annotations.Test;
16+
17+
import static org.testng.Assert.assertEquals;
18+
19+
public class MetricsTest extends BaseIntegrationTest {
20+
private MeterRegistry meterRegistry;
21+
@BeforeMethod
22+
void setUp() {
23+
meterRegistry = new SimpleMeterRegistry();
24+
Metrics.globalRegistry.add(meterRegistry);
25+
}
26+
27+
@AfterMethod
28+
void tearDown() {
29+
meterRegistry.clear();
30+
Metrics.globalRegistry.clear();
31+
}
32+
33+
@Test(groups = { "integration" }, enabled = true)
34+
public void testRegisterMetrics() {
35+
ClickHouseNode node = getServer(ClickHouseProtocol.HTTP);
36+
boolean isSecure = isCloud();
37+
Client client = new Client.Builder()
38+
.addEndpoint(Protocol.HTTP, node.getHost(), node.getPort(), isSecure)
39+
.setUsername("default")
40+
.setPassword(ClickHouseServerForTest.getPassword())
41+
.setDefaultDatabase(ClickHouseServerForTest.getDatabase())
42+
.serverSetting(ServerSettings.ASYNC_INSERT, "0")
43+
.serverSetting(ServerSettings.WAIT_END_OF_QUERY, "1")
44+
.useNewImplementation(System.getProperty("client.tests.useNewImplementation", "true").equals("true"))
45+
.addMetric(meterRegistry, "pool-test")
46+
.build();
47+
// currently there are only 5 metrics that are monitored by micrometer (out of the box)
48+
assertEquals(meterRegistry.getMeters().size(), 5);
49+
}
50+
}

0 commit comments

Comments
 (0)