Skip to content

Commit a0e043e

Browse files
committed
Merge branch 'main' into v2_reduce_init_time
2 parents e4a69bc + 8ca05b3 commit a0e043e

File tree

6 files changed

+147
-8
lines changed

6 files changed

+147
-8
lines changed

client-v2/pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@
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+
<optional>true</optional>
82+
<scope>compile</scope>
83+
</dependency>
84+
7785

7886
<!-- Test Dependencies -->
7987
<dependency>
@@ -191,6 +199,11 @@
191199
<createDependencyReducedPom>true</createDependencyReducedPom>
192200
<createSourcesJar>true</createSourcesJar>
193201
<promoteTransitiveDependencies>true</promoteTransitiveDependencies>
202+
<artifactSet>
203+
<excludes>
204+
<exclude>io.micrometer:*</exclude>
205+
</excludes>
206+
</artifactSet>
194207
<relocations>
195208
<relocation>
196209
<pattern>org.slf4j</pattern>

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

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,22 @@ public class Client implements AutoCloseable {
141141

142142
// Server context
143143
private String serverVersion;
144+
private Object metrics;
144145

145146
private Client(Set<String> endpoints, Map<String,String> configuration, boolean useNewImplementation,
146147
ExecutorService sharedOperationExecutor, ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy) {
148+
this(endpoints, configuration, useNewImplementation, sharedOperationExecutor, columnToMethodMatchingStrategy, null);
149+
}
150+
151+
private Client(Set<String> endpoints, Map<String,String> configuration, boolean useNewImplementation,
152+
ExecutorService sharedOperationExecutor, ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy, Object metrics) {
147153
this.endpoints = endpoints;
148154
this.configuration = configuration;
149155
this.readOnlyConfig = Collections.unmodifiableMap(this.configuration);
150156
this.endpoints.forEach(endpoint -> {
151157
this.serverNodes.add(ClickHouseNode.of(endpoint, this.configuration));
152158
});
159+
this.metrics = metrics;
153160
this.serializers = new ConcurrentHashMap<>();
154161
this.deserializers = new ConcurrentHashMap<>();
155162

@@ -162,7 +169,7 @@ private Client(Set<String> endpoints, Map<String,String> configuration, boolean
162169
this.sharedOperationExecutor = sharedOperationExecutor;
163170
}
164171
boolean initSslContext = getEndpoints().stream().anyMatch(s -> s.toLowerCase().contains("https://"));
165-
this.httpClientHelper = new HttpAPIClientHelper(configuration, initSslContext);
172+
this.httpClientHelper = new HttpAPIClientHelper(configuration, metrics, initSslContext);
166173
this.columnToMethodMatchingStrategy = columnToMethodMatchingStrategy;
167174
}
168175

@@ -229,7 +236,7 @@ public static class Builder {
229236

230237
private ExecutorService sharedOperationExecutor = null;
231238
private ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy;
232-
239+
private Object metric = null;
233240
public Builder() {
234241
this.endpoints = new HashSet<>();
235242
this.configuration = new HashMap<String, String>();
@@ -946,6 +953,19 @@ public Builder useBearerTokenAuth(String bearerToken) {
946953
return this;
947954
}
948955

956+
/**
957+
* Registers http client metrics with MeterRegistry.
958+
*
959+
* @param registry - metrics registry
960+
* @param name - name of metrics group
961+
* @return same instance of the builder
962+
*/
963+
public Builder registerClientMetrics(Object registry, String name) {
964+
this.metric = registry;
965+
this.configuration.put(ClientConfigProperties.METRICS_GROUP_NAME.getKey(), name);
966+
return this;
967+
}
968+
949969
public Client build() {
950970
setDefaults();
951971

@@ -1005,7 +1025,7 @@ public Client build() {
10051025
}
10061026

10071027
return new Client(this.endpoints, this.configuration, this.useNewImplementation, this.sharedOperationExecutor,
1008-
this.columnToMethodMatchingStrategy);
1028+
this.columnToMethodMatchingStrategy, this.metric);
10091029
}
10101030

10111031

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_GROUP_NAME("metrics_name"),
131134
;
132135

133136
private String key;

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
2222
import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager;
2323
import org.apache.hc.client5.http.impl.io.ManagedHttpClientConnectionFactory;
24+
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
2425
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
2526
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
2627
import org.apache.hc.client5.http.protocol.HttpClientContext;
@@ -59,6 +60,7 @@
5960
import java.io.IOException;
6061
import java.io.InputStream;
6162
import java.io.OutputStream;
63+
import java.lang.reflect.Method;
6264
import java.net.ConnectException;
6365
import java.net.InetSocketAddress;
6466
import java.net.NoRouteToHostException;
@@ -97,9 +99,10 @@ public class HttpAPIClientHelper {
9799
private final Set<ClientFaultCause> defaultRetryCauses;
98100

99101
private String defaultUserAgent;
100-
101-
public HttpAPIClientHelper(Map<String, String> configuration, boolean initSslContext) {
102+
private Object metricsRegistry;
103+
public HttpAPIClientHelper(Map<String, String> configuration, Object metricsRegistry, boolean initSslContext) {
102104
this.chConfiguration = configuration;
105+
this.metricsRegistry = metricsRegistry;
103106
this.httpClient = createHttpClient(initSslContext);
104107

105108
RequestConfig.Builder reqConfBuilder = RequestConfig.custom();
@@ -191,7 +194,6 @@ private HttpClientConnectionManager poolConnectionManager(LayeredConnectionSocke
191194
PoolingHttpClientConnectionManagerBuilder connMgrBuilder = PoolingHttpClientConnectionManagerBuilder.create()
192195
.setPoolConcurrencyPolicy(PoolConcurrencyPolicy.LAX);
193196

194-
195197
ConnectionReuseStrategy connectionReuseStrategy =
196198
ConnectionReuseStrategy.valueOf(chConfiguration.get("connection_reuse_strategy"));
197199
switch (connectionReuseStrategy) {
@@ -223,7 +225,19 @@ private HttpClientConnectionManager poolConnectionManager(LayeredConnectionSocke
223225
connMgrBuilder.setConnectionFactory(connectionFactory);
224226
connMgrBuilder.setSSLSocketFactory(sslConnectionSocketFactory);
225227
connMgrBuilder.setDefaultSocketConfig(socketConfig);
226-
return connMgrBuilder.build();
228+
PoolingHttpClientConnectionManager phccm = connMgrBuilder.build();
229+
if (metricsRegistry != null ) {
230+
try {
231+
String mGroupName = chConfiguration.getOrDefault(ClientConfigProperties.METRICS_GROUP_NAME.getKey(),
232+
"ch-http-pool");
233+
Class<?> micrometerLoader = getClass().getClassLoader().loadClass("com.clickhouse.client.api.metrics.MicrometerLoader");
234+
Method applyMethod = micrometerLoader.getDeclaredMethod("applyPoolingMetricsBinder", Object.class, String.class, PoolingHttpClientConnectionManager.class);
235+
applyMethod.invoke(micrometerLoader, metricsRegistry, mGroupName, phccm);
236+
} catch (Exception e) {
237+
LOG.error("Failed to register metrics", e);
238+
}
239+
}
240+
return phccm;
227241
}
228242

229243
public CloseableHttpClient createHttpClient(boolean initSslContext) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.clickhouse.client.api.metrics;
2+
3+
import com.clickhouse.client.api.ClientMisconfigurationException;
4+
import io.micrometer.core.instrument.MeterRegistry;
5+
import io.micrometer.core.instrument.binder.httpcomponents.hc5.PoolingHttpClientConnectionManagerMetricsBinder;
6+
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
7+
8+
public class MicrometerLoader {
9+
10+
public static void applyPoolingMetricsBinder(Object registry, String metricsGroupName, PoolingHttpClientConnectionManager phccm) {
11+
if (registry instanceof MeterRegistry) {
12+
new PoolingHttpClientConnectionManagerMetricsBinder(phccm, metricsGroupName).bindTo((MeterRegistry) registry);
13+
} else {
14+
throw new ClientMisconfigurationException("Unsupported registry type." + registry.getClass());
15+
}
16+
}
17+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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.ClientConfigProperties;
9+
import com.clickhouse.client.api.enums.Protocol;
10+
import com.clickhouse.client.api.internal.ServerSettings;
11+
import com.clickhouse.client.api.query.QueryResponse;
12+
import io.micrometer.core.instrument.Gauge;
13+
import io.micrometer.core.instrument.MeterRegistry;
14+
import io.micrometer.core.instrument.Metrics;
15+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
16+
import org.testng.Assert;
17+
import org.testng.annotations.AfterMethod;
18+
import org.testng.annotations.BeforeMethod;
19+
import org.testng.annotations.Test;
20+
21+
import static org.testng.Assert.assertEquals;
22+
23+
public class MetricsTest extends BaseIntegrationTest {
24+
private MeterRegistry meterRegistry;
25+
@BeforeMethod(groups = {"integration"})
26+
void setUp() {
27+
meterRegistry = new SimpleMeterRegistry();
28+
Metrics.globalRegistry.add(meterRegistry);
29+
}
30+
31+
@AfterMethod(groups = {"integration"})
32+
void tearDown() {
33+
meterRegistry.clear();
34+
Metrics.globalRegistry.clear();
35+
}
36+
37+
@Test(groups = { "integration" }, enabled = true)
38+
public void testRegisterMetrics() throws Exception {
39+
ClickHouseNode node = getServer(ClickHouseProtocol.HTTP);
40+
boolean isSecure = isCloud();
41+
42+
try (Client client = new Client.Builder()
43+
.addEndpoint(Protocol.HTTP, node.getHost(), node.getPort(), isSecure)
44+
.setUsername("default")
45+
.setPassword(ClickHouseServerForTest.getPassword())
46+
.setDefaultDatabase(ClickHouseServerForTest.getDatabase())
47+
.serverSetting(ServerSettings.ASYNC_INSERT, "0")
48+
.serverSetting(ServerSettings.WAIT_END_OF_QUERY, "1")
49+
.registerClientMetrics(meterRegistry, "pool-test")
50+
.build()) {
51+
52+
Gauge totalMax = meterRegistry.get("httpcomponents.httpclient.pool.total.max").gauge();
53+
Gauge available = meterRegistry.get("httpcomponents.httpclient.pool.total.connections").tags("state", "available").gauge();
54+
Gauge leased = meterRegistry.get("httpcomponents.httpclient.pool.total.connections").tags("state", "leased").gauge();
55+
56+
System.out.println("totalMax:" + totalMax.value() + ", available: " + available.value() + ", leased: " + leased.value());
57+
Assert.assertEquals((int)totalMax.value(), Integer.parseInt(ClientConfigProperties.HTTP_MAX_OPEN_CONNECTIONS.getDefaultValue()));
58+
Assert.assertEquals((int)available.value(), 1);
59+
Assert.assertEquals((int)leased.value(), 0);
60+
61+
try (QueryResponse response = client.query("SELECT 1").get()) {
62+
Assert.assertEquals((int)available.value(), 0);
63+
Assert.assertEquals((int)leased.value(), 1);
64+
}
65+
66+
Assert.assertEquals((int)available.value(), 1);
67+
Assert.assertEquals((int)leased.value(), 0);
68+
}
69+
// currently there are only 5 metrics that are monitored by micrometer (out of the box)
70+
assertEquals(meterRegistry.getMeters().size(), 5);
71+
}
72+
}

0 commit comments

Comments
 (0)