Skip to content

Commit e3057e4

Browse files
authored
[client][test] Add OTel key count metric (#1791)
Add key_count metrics in OTel for all clients. The existing tehuti metric e.g. success_request_key_count metric will still be emitted along with the key_count metrics in OTel. We tag key_count with a new 'request/response' dimensionin OTel and for response key count: - For a complete failure, the response key count will be 0 - For a partial failure via compute/batch-get streaming, the response key count will be something between 0 and the actual hit count . - For a successful request, the response key count will be same as the hit count.
1 parent 2102706 commit e3057e4

File tree

16 files changed

+223
-45
lines changed

16 files changed

+223
-45
lines changed

clients/da-vinci-client/src/main/java/com/linkedin/davinci/client/StatsAvroGenericDaVinciClient.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,19 +81,18 @@ public CompletableFuture<V> get(K key) {
8181
public CompletableFuture<V> get(K key, V reusableValue) {
8282
clientStatsForSingleGet.recordRequestKeyCount(1);
8383
return trackRequest(clientStatsForSingleGet, () -> super.get(key, reusableValue)).whenComplete((v, throwable) -> {
84-
if (throwable == null && v != null) {
85-
clientStatsForSingleGet.recordSuccessRequestKeyCount(1);
86-
}
84+
int responseKeyCount = (throwable == null && v != null) ? 1 : 0;
85+
clientStatsForSingleGet.recordResponseKeyCount(responseKeyCount);
8786
});
8887
}
8988

9089
@Override
9190
public CompletableFuture<Map<K, V>> batchGet(Set<K> keys) {
9291
clientStatsForBatchGet.recordRequestKeyCount(keys.size());
9392
return trackRequest(clientStatsForBatchGet, () -> super.batchGet(keys)).whenComplete((v, throwable) -> {
94-
if (throwable == null && v != null) {
95-
clientStatsForBatchGet.recordSuccessRequestKeyCount(v.size());
96-
}
93+
// Always record the response key count number, no matter the request is healthy or not.
94+
int responseKeyCount = (v != null) ? v.size() : 0;
95+
clientStatsForBatchGet.recordResponseKeyCount(responseKeyCount);
9796
});
9897
}
9998
}

clients/da-vinci-client/src/test/java/com/linkedin/davinci/client/StatsAvroGenericDaVinciClientTest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ public void testGet(boolean reuseApi) throws ExecutionException, InterruptedExce
6565
assertTrue(metrics.get(".test_store--healthy_request.OccurrenceRate").value() > 0);
6666
assertTrue(metrics.get(".test_store--unhealthy_request.OccurrenceRate").value() > 0);
6767
assertTrue(metrics.get(".test_store--healthy_request_latency.Avg").value() > 0);
68-
assertEquals(metrics.get(".test_store--success_request_key_count.Avg").value(), 1.0);
68+
// we have 2 requests, one success and one failure and we would record the key count for the success request as 1
69+
// and the key count for the failure request as 0.
70+
assertEquals(metrics.get(".test_store--success_request_key_count.Avg").value(), 1.0 / 2);
6971
assertEquals(metrics.get(".test_store--success_request_key_count.Max").value(), 1.0);
7072
assertTrue(metrics.get(".test_store--success_request_ratio.SimpleRatioStat").value() < 1.0);
7173
assertTrue(metrics.get(".test_store--success_request_key_ratio.SimpleRatioStat").value() < 1.0);
@@ -105,7 +107,9 @@ public void testBatchGet() throws ExecutionException, InterruptedException {
105107
assertTrue(metrics.get(".test_store--multiget_healthy_request.OccurrenceRate").value() > 0);
106108
assertTrue(metrics.get(".test_store--multiget_unhealthy_request.OccurrenceRate").value() > 0);
107109
assertTrue(metrics.get(".test_store--multiget_healthy_request_latency.Avg").value() > 0);
108-
assertEquals(metrics.get(".test_store--multiget_success_request_key_count.Avg").value(), 2.0);
110+
// We have 3 batch get requests, one success with 2 keys, one failure, and one with run time exception.
111+
// Key count for the success one is 2, failure one is 0, and the run time exception one is never recorded.
112+
assertEquals(metrics.get(".test_store--multiget_success_request_key_count.Avg").value(), 2.0 / 2);
109113
assertEquals(metrics.get(".test_store--multiget_success_request_key_count.Max").value(), 2.0);
110114
assertTrue(metrics.get(".test_store--multiget_success_request_ratio.SimpleRatioStat").value() < 1.0);
111115
assertTrue(metrics.get(".test_store--multiget_success_request_key_ratio.SimpleRatioStat").value() < 1.0);

clients/venice-client/src/main/java/com/linkedin/venice/fastclient/StatsAvroGenericStoreClient.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,9 @@ private <R> CompletableFuture<R> recordRequestMetrics(
176176
if (requestContext.responseDeserializationTime > 0) {
177177
clientStats.recordResponseDeserializationTime(requestContext.responseDeserializationTime);
178178
}
179-
clientStats.recordSuccessRequestKeyCount(requestContext.successRequestKeyCount.get());
180179
}
180+
// We want to record the response key count number, no matter the request is healthy or unhealthy.
181+
clientStats.recordResponseKeyCount(requestContext.successRequestKeyCount.get());
181182

182183
if (requestContext.noAvailableReplica) {
183184
clientStats.recordNoAvailableReplicaRequest();

clients/venice-client/src/test/java/com/linkedin/venice/fastclient/DispatchingAvroGenericStoreClientTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,8 @@ private void validateMetrics(
525525
assertFalse(metrics.get(metricPrefix + "healthy_request_latency.Avg").value() > 0);
526526
assertTrue(metrics.get(metricPrefix + "unhealthy_request.OccurrenceRate").value() > 0);
527527
assertTrue(metrics.get(metricPrefix + "unhealthy_request_latency.Avg").value() > 0);
528-
// as partial healthy request is still considered unhealthy, not incrementing the below metric
529-
assertFalse(metrics.get(metricPrefix + "success_request_key_count.Max").value() > 0);
528+
// as partial healthy request should still report success key count number.
529+
assertTrue(metrics.get(metricPrefix + "success_request_key_count.Max").value() > 0);
530530
if (batchGet) {
531531
assertTrue(metrics.get(metricPrefix + "response_ttfr.Avg").value() > 0);
532532
assertEquals(batchGetRequestContext.successRequestKeyCount.get(), (int) successKeyCount);
@@ -1294,7 +1294,7 @@ public void testComputeWithExceptionFromTransportLayerForOneRoute() throws IOExc
12941294
fail();
12951295
} catch (Exception e) {
12961296
assertTrue(e.getMessage().endsWith("At least one route did not complete"), e.getMessage());
1297-
validateComputeRequestMetrics(false, false, RequestType.COMPUTE, false, 2, 1);
1297+
validateComputeRequestMetrics(false, true, RequestType.COMPUTE, false, 2, 1);
12981298
} finally {
12991299
tearDown();
13001300
}
@@ -1525,7 +1525,7 @@ public void testStreamingComputeWithExceptionFromTransportLayerForOneRoute()
15251525
assertEquals(
15261526
response.get("test_key_1").get("name").toString(),
15271527
COMPUTE_REQUEST_VALUE_RESPONSE.get("test_key_1").get("name"));
1528-
validateComputeRequestMetrics(false, false, RequestType.COMPUTE_STREAMING, false, 2, 1);
1528+
validateComputeRequestMetrics(false, true /*partialHealthyRequest*/, RequestType.COMPUTE_STREAMING, false, 2, 1);
15291529
} finally {
15301530
tearDown();
15311531
}

clients/venice-push-job/src/test/java/com/linkedin/venice/spark/datawriter/partition/VeniceSparkPartitionerTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ public void setUp() {
4141

4242
@AfterClass(alwaysRun = true)
4343
public void tearDown() {
44-
spark.stop();
44+
if (spark != null) {
45+
spark.stop();
46+
}
4547
}
4648

4749
@Test

clients/venice-push-job/src/test/java/com/linkedin/venice/spark/datawriter/task/SparkDataWriterTaskTrackerTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ public void setUp() {
1818

1919
@AfterClass(alwaysRun = true)
2020
public void tearDown() {
21-
spark.stop();
21+
if (spark != null) {
22+
spark.stop();
23+
}
2224
}
2325

2426
@Test

clients/venice-push-job/src/test/java/com/linkedin/venice/spark/engine/SparkEngineTaskConfigProviderTest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ public void setUp() {
3333

3434
@AfterClass(alwaysRun = true)
3535
public void tearDown() {
36-
sparkContext.close();
37-
spark.stop();
36+
if (sparkContext != null) {
37+
sparkContext.close();
38+
}
39+
if (spark != null) {
40+
spark.stop();
41+
}
3842
}
3943

4044
@Test

clients/venice-thin-client/src/main/java/com/linkedin/venice/client/stats/BasicClientStats.java

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
import static com.linkedin.venice.stats.dimensions.HttpResponseStatusCodeCategory.getVeniceHttpResponseStatusCodeCategory;
44
import static com.linkedin.venice.stats.dimensions.HttpResponseStatusEnum.transformIntToHttpResponseStatusEnum;
5+
import static com.linkedin.venice.stats.dimensions.MessageType.REQUEST;
6+
import static com.linkedin.venice.stats.dimensions.MessageType.RESPONSE;
57
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.HTTP_RESPONSE_STATUS_CODE;
68
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.HTTP_RESPONSE_STATUS_CODE_CATEGORY;
9+
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.VENICE_MESSAGE_TYPE;
710
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.VENICE_REQUEST_METHOD;
811
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.VENICE_RESPONSE_STATUS_CODE_CATEGORY;
912
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.VENICE_STORE_NAME;
@@ -25,6 +28,7 @@
2528
import com.linkedin.venice.stats.VeniceOpenTelemetryMetricsRepository;
2629
import com.linkedin.venice.stats.dimensions.HttpResponseStatusCodeCategory;
2730
import com.linkedin.venice.stats.dimensions.HttpResponseStatusEnum;
31+
import com.linkedin.venice.stats.dimensions.MessageType;
2832
import com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions;
2933
import com.linkedin.venice.stats.dimensions.VeniceResponseStatusCategory;
3034
import com.linkedin.venice.stats.metrics.MetricEntity;
@@ -72,8 +76,8 @@ public class BasicClientStats extends AbstractVeniceHttpStats {
7276
private final MetricEntityStateOneEnum<VeniceResponseStatusCategory> unhealthyRequestMetricForDavinciClient;
7377
private final MetricEntityStateOneEnum<VeniceResponseStatusCategory> healthyLatencyMetricForDavinciClient;
7478
private final MetricEntityStateOneEnum<VeniceResponseStatusCategory> unhealthyLatencyMetricForDavinciClient;
75-
private final Sensor requestKeyCountSensor;
76-
private final Sensor successRequestKeyCountSensor;
79+
private final MetricEntityStateOneEnum<MessageType> requestKeyCount;
80+
private final MetricEntityStateOneEnum<MessageType> successResponseKeyCount;
7781
private final Sensor successRequestRatioSensor;
7882
private final Sensor successRequestKeyRatioSensor;
7983
private final Rate requestRate = new OccurrenceRate();
@@ -127,8 +131,9 @@ protected BasicClientStats(
127131
// requestSensor will be a derived metric in OTel
128132
requestSensor = registerSensor("request", requestRate);
129133
Rate healthyRequestRate = new OccurrenceRate();
134+
Rate requestKeyCountRate = new Rate();
130135

131-
if (clientType.equals(ClientType.DAVINCI_CLIENT)) {
136+
if (ClientType.isDavinciClient(clientType)) {
132137
healthyRequestMetricForDavinciClient = MetricEntityStateOneEnum.create(
133138
BasicClientMetricEntity.CALL_COUNT_DVC.getMetricEntity(),
134139
otelRepository,
@@ -171,6 +176,7 @@ protected BasicClientStats(
171176
getFullMetricName(BasicClientTehutiMetricName.UNHEALTHY_REQUEST_LATENCY.getMetricName()))),
172177
getBaseDimensionsMap(),
173178
VeniceResponseStatusCategory.class);
179+
174180
healthyRequestMetric = null;
175181
unhealthyRequestMetric = null;
176182
healthyLatencyMetric = null;
@@ -231,16 +237,29 @@ protected BasicClientStats(
231237
unhealthyLatencyMetricForDavinciClient = null;
232238
}
233239

240+
// request key count
241+
requestKeyCount = MetricEntityStateOneEnum.create(
242+
BasicClientMetricEntity.KEY_COUNT.getMetricEntity(),
243+
getOtelRepository(),
244+
this::registerSensor,
245+
BasicClientTehutiMetricName.REQUEST_KEY_COUNT,
246+
Arrays.asList(requestKeyCountRate, new Avg(), new Max()),
247+
baseDimensionsMap,
248+
MessageType.class);
249+
250+
successResponseKeyCount = MetricEntityStateOneEnum.create(
251+
BasicClientMetricEntity.KEY_COUNT.getMetricEntity(),
252+
otelRepository,
253+
this::registerSensor,
254+
BasicClientTehutiMetricName.SUCCESS_REQUEST_KEY_COUNT,
255+
Arrays.asList(successRequestKeyCountRate, new Avg(), new Max()),
256+
baseDimensionsMap,
257+
MessageType.class);
258+
234259
// successRequestRatioSensor will be a derived metric in OTel
235260
successRequestRatioSensor =
236261
registerSensor(new TehutiUtils.SimpleRatioStat(healthyRequestRate, requestRate, "success_request_ratio"));
237262

238-
// key count
239-
Rate requestKeyCountRate = new Rate();
240-
requestKeyCountSensor = registerSensor("request_key_count", requestKeyCountRate, new Avg(), new Max());
241-
successRequestKeyCountSensor =
242-
registerSensor("success_request_key_count", successRequestKeyCountRate, new Avg(), new Max());
243-
244263
successRequestKeyRatioSensor = registerSensor(
245264
new TehutiUtils.SimpleRatioStat(successRequestKeyCountRate, requestKeyCountRate, "success_request_key_ratio"));
246265
}
@@ -295,11 +314,11 @@ public void emitUnhealthyRequestMetricsForDavinciClient(double latency) {
295314
}
296315

297316
public void recordRequestKeyCount(int keyCount) {
298-
requestKeyCountSensor.record(keyCount);
317+
requestKeyCount.record(keyCount, REQUEST);
299318
}
300319

301-
public void recordSuccessRequestKeyCount(int successKeyCount) {
302-
successRequestKeyCountSensor.record(successKeyCount);
320+
public void recordResponseKeyCount(int keyCount) {
321+
successResponseKeyCount.record(keyCount, RESPONSE);
303322
}
304323

305324
protected final Rate getRequestRate() {
@@ -360,7 +379,8 @@ private Map<VeniceMetricsDimensions, String> getBaseDimensionsMap() {
360379
* Metric names for tehuti metrics used in this class.
361380
*/
362381
public enum BasicClientTehutiMetricName implements TehutiMetricNameEnum {
363-
HEALTHY_REQUEST, UNHEALTHY_REQUEST, HEALTHY_REQUEST_LATENCY, UNHEALTHY_REQUEST_LATENCY;
382+
HEALTHY_REQUEST, UNHEALTHY_REQUEST, HEALTHY_REQUEST_LATENCY, UNHEALTHY_REQUEST_LATENCY, REQUEST_KEY_COUNT,
383+
SUCCESS_REQUEST_KEY_COUNT;
364384

365385
private final String metricName;
366386

@@ -400,6 +420,13 @@ public enum BasicClientMetricEntity implements ModuleMetricEntityInterface {
400420
HTTP_RESPONSE_STATUS_CODE_CATEGORY,
401421
VENICE_RESPONSE_STATUS_CODE_CATEGORY)
402422
),
423+
/**
424+
* Count of keys for venice client request and response.
425+
*/
426+
KEY_COUNT(
427+
MetricType.HISTOGRAM, MetricUnit.NUMBER, "Count of keys for venice client request and response",
428+
setOf(VENICE_STORE_NAME, VENICE_REQUEST_METHOD, VENICE_MESSAGE_TYPE)
429+
),
403430
/**
404431
* Count of all DaVinci requests: as DaVinci is local reads, we do not track HTTP response codes
405432
* But keeping the same name call_count across all clients for consistency

clients/venice-thin-client/src/main/java/com/linkedin/venice/client/store/StatTrackingStoreClient.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ private static void handleMetricTrackingForStreamingCallback(
264264
} else {
265265
clientStats.emitHealthyRequestMetrics(latency, successKeyCnt);
266266
}
267-
clientStats.recordSuccessRequestKeyCount(successKeyCnt);
267+
clientStats.recordResponseKeyCount(successKeyCnt);
268268
clientStats.recordSuccessDuplicateRequestKeyCount(duplicateEntryCnt);
269269
}
270270

@@ -289,7 +289,7 @@ public ComputeRequestBuilder<K> compute() throws VeniceClientException {
289289
}
290290

291291
clientStats.emitHealthyRequestMetrics(latency, value);
292-
clientStats.recordSuccessRequestKeyCount(getSuccessfulKeyCount(value));
292+
clientStats.recordResponseKeyCount(getSuccessfulKeyCount(value));
293293
return value;
294294
};
295295
}

clients/venice-thin-client/src/test/java/com/linkedin/venice/client/stats/BasicClientStatsTest.java

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
import static com.linkedin.venice.stats.VeniceMetricsRepository.getVeniceMetricsRepository;
88
import static com.linkedin.venice.stats.dimensions.HttpResponseStatusCodeCategory.getVeniceHttpResponseStatusCodeCategory;
99
import static com.linkedin.venice.stats.dimensions.HttpResponseStatusEnum.transformIntToHttpResponseStatusEnum;
10+
import static com.linkedin.venice.stats.dimensions.MessageType.*;
1011
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.HTTP_RESPONSE_STATUS_CODE;
1112
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.HTTP_RESPONSE_STATUS_CODE_CATEGORY;
13+
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.VENICE_MESSAGE_TYPE;
1214
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.VENICE_REQUEST_METHOD;
1315
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.VENICE_REQUEST_RETRY_TYPE;
1416
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.VENICE_RESPONSE_STATUS_CODE_CATEGORY;
1517
import static com.linkedin.venice.stats.dimensions.VeniceMetricsDimensions.VENICE_STORE_NAME;
18+
import static com.linkedin.venice.stats.dimensions.VeniceResponseStatusCategory.SUCCESS;
1619
import static com.linkedin.venice.utils.OpenTelemetryDataPointTestUtils.getExponentialHistogramPointData;
1720
import static com.linkedin.venice.utils.OpenTelemetryDataPointTestUtils.getLongPointData;
1821
import static com.linkedin.venice.utils.OpenTelemetryDataPointTestUtils.validateExponentialHistogramPointData;
@@ -25,12 +28,14 @@
2528
import com.linkedin.venice.client.store.ClientConfig;
2629
import com.linkedin.venice.stats.ClientType;
2730
import com.linkedin.venice.stats.VeniceMetricsRepository;
31+
import com.linkedin.venice.stats.dimensions.MessageType;
2832
import com.linkedin.venice.stats.dimensions.RequestRetryType;
2933
import com.linkedin.venice.stats.dimensions.VeniceResponseStatusCategory;
3034
import com.linkedin.venice.stats.metrics.MetricEntity;
3135
import com.linkedin.venice.stats.metrics.MetricType;
3236
import com.linkedin.venice.stats.metrics.MetricUnit;
3337
import com.linkedin.venice.stats.metrics.ModuleMetricEntityInterface;
38+
import com.linkedin.venice.utils.DataProviderUtils;
3439
import com.linkedin.venice.utils.Utils;
3540
import io.opentelemetry.api.common.Attributes;
3641
import io.opentelemetry.api.common.AttributesBuilder;
@@ -86,13 +91,7 @@ public void testEmitHealthyMetrics() {
8691
stats.emitHealthyRequestMetrics(90.0, 2);
8792

8893
validateTehutiMetrics(stats.getMetricsRepository(), ".test_store", true, 90.0);
89-
validateOtelMetrics(
90-
inMemoryMetricReader,
91-
"test_store",
92-
SC_OK,
93-
VeniceResponseStatusCategory.SUCCESS,
94-
90.0,
95-
THIN_CLIENT.getMetricsPrefix());
94+
validateOtelMetrics(inMemoryMetricReader, "test_store", SC_OK, SUCCESS, 90.0, THIN_CLIENT.getMetricsPrefix());
9695
}
9796

9897
@Test
@@ -102,12 +101,7 @@ public void testEmitHealthyRequestMetricsForDavinciClient() {
102101
stats.emitHealthyRequestMetricsForDavinciClient(90.0);
103102

104103
validateTehutiMetrics(stats.getMetricsRepository(), ".test_store", true, 90.0);
105-
validateOtelMetrics(
106-
inMemoryMetricReader,
107-
"test_store",
108-
VeniceResponseStatusCategory.SUCCESS,
109-
90.0,
110-
DAVINCI_CLIENT.getMetricsPrefix());
104+
validateOtelMetrics(inMemoryMetricReader, "test_store", SUCCESS, 90.0, DAVINCI_CLIENT.getMetricsPrefix());
111105
}
112106

113107
@Test
@@ -159,6 +153,42 @@ public void testEmitUnhealthyRequestMetricsForDavinciClientWithWrongClientType()
159153
Assert.assertFalse(metrics.get(".test_store--request.OccurrenceRate").value() > 0.0);
160154
}
161155

156+
@Test(dataProviderClass = DataProviderUtils.class, dataProvider = "True-and-False")
157+
public void testKeyCountMetrics(boolean isRequest) {
158+
for (ClientType client: ClientType.values()) {
159+
// verify that the following works for all client types.
160+
InMemoryMetricReader inMemoryMetricReader = InMemoryMetricReader.create();
161+
BasicClientStats stats = createStats(inMemoryMetricReader, client);
162+
163+
int keyCount = 10;
164+
165+
if (isRequest) {
166+
stats.recordRequestKeyCount(keyCount);
167+
} else {
168+
stats.recordResponseKeyCount(keyCount);
169+
}
170+
171+
// Check Tehuti metrics
172+
Map<String, ? extends Metric> metrics = stats.getMetricsRepository().metrics();
173+
String storeName = "test_store";
174+
if (isRequest) {
175+
Assert
176+
.assertEquals((int) metrics.get(String.format(".%s--request_key_count.Max", storeName)).value(), keyCount);
177+
} else {
178+
Assert.assertEquals(
179+
(int) metrics.get(String.format(".%s--success_request_key_count.Max", storeName)).value(),
180+
keyCount);
181+
}
182+
183+
// Check OpenTelemetry metrics
184+
Collection<MetricData> metricsData = inMemoryMetricReader.collectAllMetrics();
185+
Attributes expectedAttr = getAttributes(storeName, isRequest ? REQUEST : RESPONSE);
186+
ExponentialHistogramPointData data =
187+
getExponentialHistogramPointData(metricsData, "key_count", client.getMetricsPrefix());
188+
validateExponentialHistogramPointData(data, keyCount, keyCount, 1, keyCount, expectedAttr);
189+
}
190+
}
191+
162192
@Test
163193
public void testEmitRequestRetryMetrics() {
164194
InMemoryMetricReader inMemoryMetricReader = InMemoryMetricReader.create();
@@ -299,6 +329,14 @@ public void testClientMetricEntities() {
299329
MetricUnit.MILLISECOND,
300330
"Latency for all DaVinci Client responses",
301331
Utils.setOf(VENICE_STORE_NAME, VENICE_REQUEST_METHOD, VENICE_RESPONSE_STATUS_CODE_CATEGORY)));
332+
expectedMetrics.put(
333+
BasicClientStats.BasicClientMetricEntity.KEY_COUNT,
334+
new MetricEntity(
335+
"key_count",
336+
MetricType.HISTOGRAM,
337+
MetricUnit.NUMBER,
338+
"Count of keys for venice client request and response",
339+
Utils.setOf(VENICE_STORE_NAME, VENICE_REQUEST_METHOD, VENICE_MESSAGE_TYPE)));
302340
expectedMetrics.put(
303341
ClientMetricEntity.RETRY_COUNT,
304342
new MetricEntity(
@@ -405,4 +443,12 @@ private Attributes getExpectedAttributes(
405443
}
406444
return builder.build();
407445
}
446+
447+
private Attributes getAttributes(String storeName, MessageType type) {
448+
AttributesBuilder builder = Attributes.builder()
449+
.put(VENICE_STORE_NAME.getDimensionNameInDefaultFormat(), storeName)
450+
.put(VENICE_REQUEST_METHOD.getDimensionNameInDefaultFormat(), SINGLE_GET.getDimensionValue())
451+
.put(VENICE_MESSAGE_TYPE.getDimensionNameInDefaultFormat(), type.getDimensionValue());
452+
return builder.build();
453+
}
408454
}

0 commit comments

Comments
 (0)