Skip to content

Commit 6cd007d

Browse files
authored
xds: add the missing xds.authority metric (#12018)
This completes the [XDS client metrics](https://github.com/grpc/proposal/blob/master/A78-grpc-metrics-wrr-pf-xds.md#xdsclient) by adding the remaining grpc.xds.authority metric.
1 parent 9619453 commit 6cd007d

File tree

4 files changed

+80
-51
lines changed

4 files changed

+80
-51
lines changed

xds/src/main/java/io/grpc/xds/XdsClientMetricReporterImpl.java

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ final class XdsClientMetricReporterImpl implements XdsClientMetricReporter {
9090
Arrays.asList("grpc.target", "grpc.xds.server"), Collections.emptyList(), false);
9191
RESOURCES_GAUGE = metricInstrumentRegistry.registerLongGauge("grpc.xds_client.resources",
9292
"EXPERIMENTAL. Number of xDS resources.", "{resource}",
93-
Arrays.asList("grpc.target", "grpc.xds.cache_state",
93+
Arrays.asList("grpc.target", "grpc.xds.authority", "grpc.xds.cache_state",
9494
"grpc.xds.resource_type"), Collections.emptyList(), false);
9595
}
9696

@@ -161,15 +161,32 @@ private void computeAndReportResourceCounts(
161161
for (Map.Entry<XdsResourceType<?>, Map<String, ResourceMetadata>> metadataByTypeEntry :
162162
metadataByType.entrySet()) {
163163
XdsResourceType<?> type = metadataByTypeEntry.getKey();
164+
Map<String, ResourceMetadata> resources = metadataByTypeEntry.getValue();
164165

165-
Map<String, Long> resourceCountsByState = new HashMap<>();
166-
for (ResourceMetadata metadata : metadataByTypeEntry.getValue().values()) {
166+
Map<String, Map<String, Long>> resourceCountsByAuthorityAndState = new HashMap<>();
167+
for (Map.Entry<String, ResourceMetadata> resourceEntry : resources.entrySet()) {
168+
String resourceName = resourceEntry.getKey();
169+
ResourceMetadata metadata = resourceEntry.getValue();
170+
String authority = XdsClient.getAuthorityFromResourceName(resourceName);
167171
String cacheState = cacheStateFromResourceStatus(metadata.getStatus(), metadata.isCached());
168-
resourceCountsByState.compute(cacheState, (k, v) -> (v == null) ? 1 : v + 1);
172+
resourceCountsByAuthorityAndState
173+
.computeIfAbsent(authority, k -> new HashMap<>())
174+
.merge(cacheState, 1L, Long::sum);
169175
}
170176

171-
resourceCountsByState.forEach((cacheState, count) ->
172-
callback.reportResourceCountGauge(count, cacheState, type.typeUrl()));
177+
// Report metrics
178+
for (Map.Entry<String, Map<String, Long>> authorityEntry
179+
: resourceCountsByAuthorityAndState.entrySet()) {
180+
String authority = authorityEntry.getKey();
181+
Map<String, Long> stateCounts = authorityEntry.getValue();
182+
183+
for (Map.Entry<String, Long> stateEntry : stateCounts.entrySet()) {
184+
String cacheState = stateEntry.getKey();
185+
Long count = stateEntry.getValue();
186+
187+
callback.reportResourceCountGauge(count, authority, cacheState, type.typeUrl());
188+
}
189+
}
173190
}
174191
}
175192

@@ -199,11 +216,12 @@ static final class MetricReporterCallback implements ServerConnectionCallback {
199216
this.target = target;
200217
}
201218

202-
// TODO(dnvindhya): include the "authority" label once xds.authority is available.
203-
void reportResourceCountGauge(long resourceCount, String cacheState,
219+
void reportResourceCountGauge(long resourceCount, String authority, String cacheState,
204220
String resourceType) {
221+
// authority = #old, for non-xdstp resource names
205222
recorder.recordLongGauge(RESOURCES_GAUGE, resourceCount,
206-
Arrays.asList(target, cacheState, resourceType), Collections.emptyList());
223+
Arrays.asList(target, authority == null ? "#old" : authority, cacheState, resourceType),
224+
Collections.emptyList());
207225
}
208226

209227
@Override

xds/src/main/java/io/grpc/xds/client/XdsClient.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,23 @@ public static String percentEncodePath(String input) {
118118
return Joiner.on('/').join(encodedSegs);
119119
}
120120

121+
/**
122+
* Returns the authority from the resource name.
123+
*/
124+
public static String getAuthorityFromResourceName(String resourceNames) {
125+
String authority;
126+
if (resourceNames.startsWith(XDSTP_SCHEME)) {
127+
URI uri = URI.create(resourceNames);
128+
authority = uri.getAuthority();
129+
if (authority == null) {
130+
authority = "";
131+
}
132+
} else {
133+
authority = null;
134+
}
135+
return authority;
136+
}
137+
121138
public interface ResourceUpdate {}
122139

123140
/**

xds/src/main/java/io/grpc/xds/client/XdsClientImpl.java

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import static com.google.common.base.Preconditions.checkArgument;
2020
import static com.google.common.base.Preconditions.checkNotNull;
21-
import static io.grpc.xds.client.Bootstrapper.XDSTP_SCHEME;
2221
import static io.grpc.xds.client.XdsResourceType.ParsedResource;
2322
import static io.grpc.xds.client.XdsResourceType.ValidatedResourceUpdate;
2423

@@ -43,7 +42,6 @@
4342
import io.grpc.xds.client.XdsClient.ResourceStore;
4443
import io.grpc.xds.client.XdsLogger.XdsLogLevel;
4544
import java.io.IOException;
46-
import java.net.URI;
4745
import java.util.ArrayList;
4846
import java.util.Collection;
4947
import java.util.Collections;
@@ -530,21 +528,6 @@ public Map<ServerInfo, LoadReportClient> getServerLrsClientMap() {
530528
return ImmutableMap.copyOf(serverLrsClientMap);
531529
}
532530

533-
private String getAuthority(String resource) {
534-
String authority;
535-
if (resource.startsWith(XDSTP_SCHEME)) {
536-
URI uri = URI.create(resource);
537-
authority = uri.getAuthority();
538-
if (authority == null) {
539-
authority = "";
540-
}
541-
} else {
542-
authority = null;
543-
}
544-
545-
return authority;
546-
}
547-
548531
@Nullable
549532
private ImmutableList<ServerInfo> getServerInfos(String authority) {
550533
if (authority != null) {
@@ -698,7 +681,7 @@ private final class ResourceSubscriber<T extends ResourceUpdate> {
698681
syncContext.throwIfNotInThisSynchronizationContext();
699682
this.type = type;
700683
this.resource = resource;
701-
this.authority = getAuthority(resource);
684+
this.authority = getAuthorityFromResourceName(resource);
702685
if (getServerInfos(authority) == null) {
703686
this.errorDescription = "Wrong configuration: xds server does not exist for resource "
704687
+ resource;

xds/src/test/java/io/grpc/xds/XdsClientMetricReporterImplTest.java

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
public class XdsClientMetricReporterImplTest {
7777

7878
private static final String target = "test-target";
79+
private static final String authority = "test-authority";
7980
private static final String server = "trafficdirector.googleapis.com";
8081
private static final String resourceTypeUrl =
8182
"resourceTypeUrl.googleapis.com/envoy.config.cluster.v3.Cluster";
@@ -101,7 +102,6 @@ public void setUp() {
101102

102103
@Test
103104
public void reportResourceUpdates() {
104-
// TODO(dnvindhya): add the "authority" label once available.
105105
reporter.reportResourceUpdates(10, 5, server, resourceTypeUrl);
106106
verify(mockMetricRecorder).addLongCounter(
107107
eqMetricInstrumentName("grpc.xds_client.resource_updates_valid"), eq((long) 10),
@@ -175,8 +175,8 @@ public void setXdsClient_reportCallbackMetrics_resourceCountsFails() {
175175
public void metricGauges() {
176176
SettableFuture<Void> future = SettableFuture.create();
177177
future.set(null);
178-
when(mockXdsClient.getSubscribedResourcesMetadataSnapshot()).thenReturn(Futures.immediateFuture(
179-
ImmutableMap.of()));
178+
when(mockXdsClient.getSubscribedResourcesMetadataSnapshot())
179+
.thenReturn(Futures.immediateFuture(ImmutableMap.of()));
180180
when(mockXdsClient.reportServerConnections(any(ServerConnectionCallback.class)))
181181
.thenReturn(future);
182182
reporter.setXdsClient(mockXdsClient);
@@ -199,13 +199,15 @@ public void metricGauges() {
199199

200200
// Verify that reportResourceCounts and reportServerConnections were called
201201
// with the captured callback
202-
callback.reportResourceCountGauge(10, "acked", resourceTypeUrl);
202+
callback.reportResourceCountGauge(10, "MrPotatoHead",
203+
"acked", resourceTypeUrl);
203204
inOrder.verify(mockBatchRecorder)
204205
.recordLongGauge(eqMetricInstrumentName("grpc.xds_client.resources"), eq(10L), any(),
205206
any());
206207
callback.reportServerConnectionGauge(true, "xdsServer");
207208
inOrder.verify(mockBatchRecorder)
208-
.recordLongGauge(eqMetricInstrumentName("grpc.xds_client.connected"), eq(1L), any(), any());
209+
.recordLongGauge(eqMetricInstrumentName("grpc.xds_client.connected"),
210+
eq(1L), any(), any());
209211

210212
inOrder.verifyNoMoreInteractions();
211213
}
@@ -222,10 +224,10 @@ public void metricReporterCallback() {
222224
eq(Lists.newArrayList()));
223225

224226
String cacheState = "requested";
225-
callback.reportResourceCountGauge(10, cacheState, resourceTypeUrl);
227+
callback.reportResourceCountGauge(10, authority, cacheState, resourceTypeUrl);
226228
verify(mockBatchRecorder, times(1)).recordLongGauge(
227229
eqMetricInstrumentName("grpc.xds_client.resources"), eq(10L),
228-
eq(Arrays.asList(target, cacheState, resourceTypeUrl)),
230+
eq(Arrays.asList(target, authority, cacheState, resourceTypeUrl)),
229231
eq(Collections.emptyList()));
230232
}
231233

@@ -236,32 +238,31 @@ public void reportCallbackMetrics_computeAndReportResourceCounts() {
236238
XdsResourceType<?> routeConfigResource = XdsRouteConfigureResource.getInstance();
237239
XdsResourceType<?> clusterResource = XdsClusterResource.getInstance();
238240

239-
Any rawListener =
240-
Any.pack(Listener.newBuilder().setName("listener.googleapis.com").build());
241+
Any rawListener = Any.pack(Listener.newBuilder().setName("listener.googleapis.com").build());
241242
long nanosLastUpdate = 1577923199_606042047L;
242243

243244
Map<String, ResourceMetadata> ldsResourceMetadataMap = new HashMap<>();
244-
ldsResourceMetadataMap.put("resource1",
245+
ldsResourceMetadataMap.put("xdstp://authority1",
245246
ResourceMetadata.newResourceMetadataRequested());
246-
ResourceMetadata ackedLdsResource = ResourceMetadata.newResourceMetadataAcked(rawListener, "42",
247-
nanosLastUpdate);
247+
ResourceMetadata ackedLdsResource =
248+
ResourceMetadata.newResourceMetadataAcked(rawListener, "42", nanosLastUpdate);
248249
ldsResourceMetadataMap.put("resource2", ackedLdsResource);
249250
ldsResourceMetadataMap.put("resource3",
250251
ResourceMetadata.newResourceMetadataAcked(rawListener, "43", nanosLastUpdate));
251-
ldsResourceMetadataMap.put("resource4",
252-
ResourceMetadata.newResourceMetadataNacked(ackedLdsResource, "44", nanosLastUpdate,
253-
"nacked after previous ack", true));
252+
ldsResourceMetadataMap.put("xdstp:/no_authority",
253+
ResourceMetadata.newResourceMetadataNacked(ackedLdsResource, "44",
254+
nanosLastUpdate, "nacked after previous ack", true));
254255

255256
Map<String, ResourceMetadata> rdsResourceMetadataMap = new HashMap<>();
256257
ResourceMetadata requestedRdsResourceMetadata = ResourceMetadata.newResourceMetadataRequested();
257-
rdsResourceMetadataMap.put("resource5",
258+
rdsResourceMetadataMap.put("xdstp://authority5",
258259
ResourceMetadata.newResourceMetadataNacked(requestedRdsResourceMetadata, "24",
259260
nanosLastUpdate, "nacked after request", false));
260-
rdsResourceMetadataMap.put("resource6",
261+
rdsResourceMetadataMap.put("xdstp://authority6",
261262
ResourceMetadata.newResourceMetadataDoesNotExist());
262263

263264
Map<String, ResourceMetadata> cdsResourceMetadataMap = new HashMap<>();
264-
cdsResourceMetadataMap.put("resource7", ResourceMetadata.newResourceMetadataUnknown());
265+
cdsResourceMetadataMap.put("xdstp://authority7", ResourceMetadata.newResourceMetadataUnknown());
265266

266267
metadataByType.put(listenerResource, ldsResourceMetadataMap);
267268
metadataByType.put(routeConfigResource, rdsResourceMetadataMap);
@@ -281,24 +282,34 @@ public void reportCallbackMetrics_computeAndReportResourceCounts() {
281282

282283
// LDS resource requested
283284
verify(mockBatchRecorder).recordLongGauge(eqMetricInstrumentName("grpc.xds_client.resources"),
284-
eq(1L), eq(Arrays.asList(target, "requested", listenerResource.typeUrl())), any());
285+
eq(1L),
286+
eq(Arrays.asList(target, "authority1", "requested", listenerResource.typeUrl())), any());
285287
// LDS resources acked
288+
// authority = #old, for non-xdstp resource names
286289
verify(mockBatchRecorder).recordLongGauge(eqMetricInstrumentName("grpc.xds_client.resources"),
287-
eq(2L), eq(Arrays.asList(target, "acked", listenerResource.typeUrl())), any());
290+
eq(2L),
291+
eq(Arrays.asList(target, "#old", "acked", listenerResource.typeUrl())), any());
288292
// LDS resource nacked but cached
293+
// "" for missing authority in the resource name
289294
verify(mockBatchRecorder).recordLongGauge(eqMetricInstrumentName("grpc.xds_client.resources"),
290-
eq(1L), eq(Arrays.asList(target, "nacked_but_cached", listenerResource.typeUrl())), any());
295+
eq(1L),
296+
eq(Arrays.asList(target, "", "nacked_but_cached", listenerResource.typeUrl())), any());
291297

292298
// RDS resource nacked
293299
verify(mockBatchRecorder).recordLongGauge(eqMetricInstrumentName("grpc.xds_client.resources"),
294-
eq(1L), eq(Arrays.asList(target, "nacked", routeConfigResource.typeUrl())), any());
300+
eq(1L),
301+
eq(Arrays.asList(target, "authority5", "nacked", routeConfigResource.typeUrl())), any());
295302
// RDS resource does not exist
296303
verify(mockBatchRecorder).recordLongGauge(eqMetricInstrumentName("grpc.xds_client.resources"),
297-
eq(1L), eq(Arrays.asList(target, "does_not_exist", routeConfigResource.typeUrl())), any());
304+
eq(1L),
305+
eq(Arrays.asList(target, "authority6", "does_not_exist", routeConfigResource.typeUrl())),
306+
any());
298307

299308
// CDS resource unknown
300309
verify(mockBatchRecorder).recordLongGauge(eqMetricInstrumentName("grpc.xds_client.resources"),
301-
eq(1L), eq(Arrays.asList(target, "unknown", clusterResource.typeUrl())), any());
310+
eq(1L),
311+
eq(Arrays.asList(target, "authority7", "unknown", clusterResource.typeUrl())),
312+
any());
302313
verifyNoMoreInteractions(mockBatchRecorder);
303314
}
304315

0 commit comments

Comments
 (0)