• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #19563

26 Nov 2024 12:47AM UTC coverage: 88.559% (-0.02%) from 88.582%
#19563

push

github

web-flow
xds: Add counter and gauge metrics  (#11661)

Adds the following xDS client metrics defined in [A78](https://github.com/grpc/proposal/blob/master/A78-grpc-metrics-wrr-pf-xds.md#xdsclient).

Counters
- grpc.xds_client.server_failure
- grpc.xds_client.resource_updates_valid
- grpc.xds_client.resource_updates_invalid

Gauges
- grpc.xds_client.connected
- grpc.xds_client.resources

33368 of 37679 relevant lines covered (88.56%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.83
/../xds/src/main/java/io/grpc/xds/SharedXdsClientPoolProvider.java
1
/*
2
 * Copyright 2020 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.xds;
18

19
import static com.google.common.base.Preconditions.checkNotNull;
20
import static io.grpc.xds.GrpcXdsTransportFactory.DEFAULT_XDS_TRANSPORT_FACTORY;
21

22
import com.google.common.annotations.VisibleForTesting;
23
import com.google.common.collect.ImmutableList;
24
import io.grpc.MetricRecorder;
25
import io.grpc.internal.ExponentialBackoffPolicy;
26
import io.grpc.internal.GrpcUtil;
27
import io.grpc.internal.ObjectPool;
28
import io.grpc.internal.SharedResourceHolder;
29
import io.grpc.internal.TimeProvider;
30
import io.grpc.xds.client.Bootstrapper;
31
import io.grpc.xds.client.Bootstrapper.BootstrapInfo;
32
import io.grpc.xds.client.XdsClient;
33
import io.grpc.xds.client.XdsClientImpl;
34
import io.grpc.xds.client.XdsInitializationException;
35
import io.grpc.xds.internal.security.TlsContextManagerImpl;
36
import java.util.Map;
37
import java.util.concurrent.ConcurrentHashMap;
38
import java.util.concurrent.ScheduledExecutorService;
39
import java.util.concurrent.atomic.AtomicReference;
40
import java.util.logging.Level;
41
import java.util.logging.Logger;
42
import javax.annotation.Nullable;
43
import javax.annotation.concurrent.GuardedBy;
44
import javax.annotation.concurrent.ThreadSafe;
45

46
/**
47
 * The global factory for creating a singleton {@link XdsClient} instance to be used by all gRPC
48
 * clients in the process.
49
 */
50
@ThreadSafe
51
final class SharedXdsClientPoolProvider implements XdsClientPoolFactory {
52
  private static final boolean LOG_XDS_NODE_ID = Boolean.parseBoolean(
1✔
53
      System.getenv("GRPC_LOG_XDS_NODE_ID"));
1✔
54
  private static final Logger log = Logger.getLogger(XdsClientImpl.class.getName());
1✔
55
  private static final ExponentialBackoffPolicy.Provider BACKOFF_POLICY_PROVIDER =
1✔
56
      new ExponentialBackoffPolicy.Provider();
57

58
  private final Bootstrapper bootstrapper;
59
  private final Object lock = new Object();
1✔
60
  private final AtomicReference<Map<String, ?>> bootstrapOverride = new AtomicReference<>();
1✔
61
  private final Map<String, ObjectPool<XdsClient>> targetToXdsClientMap = new ConcurrentHashMap<>();
1✔
62

63
  SharedXdsClientPoolProvider() {
64
    this(new GrpcBootstrapperImpl());
1✔
65
  }
1✔
66

67
  @VisibleForTesting
68
  SharedXdsClientPoolProvider(Bootstrapper bootstrapper) {
1✔
69
    this.bootstrapper = checkNotNull(bootstrapper, "bootstrapper");
1✔
70
  }
1✔
71

72
  static SharedXdsClientPoolProvider getDefaultProvider() {
73
    return SharedXdsClientPoolProviderHolder.instance;
1✔
74
  }
75

76
  @Override
77
  public void setBootstrapOverride(Map<String, ?> bootstrap) {
78
    bootstrapOverride.set(bootstrap);
1✔
79
  }
1✔
80

81
  @Override
82
  @Nullable
83
  public ObjectPool<XdsClient> get(String target) {
84
    return targetToXdsClientMap.get(target);
1✔
85
  }
86

87
  @Override
88
  public ObjectPool<XdsClient> getOrCreate(String target, MetricRecorder metricRecorder)
89
      throws XdsInitializationException {
90
    ObjectPool<XdsClient> ref = targetToXdsClientMap.get(target);
1✔
91
    if (ref == null) {
1✔
92
      synchronized (lock) {
1✔
93
        ref = targetToXdsClientMap.get(target);
1✔
94
        if (ref == null) {
1✔
95
          BootstrapInfo bootstrapInfo;
96
          Map<String, ?> rawBootstrap = bootstrapOverride.get();
1✔
97
          if (rawBootstrap != null) {
1✔
98
            bootstrapInfo = bootstrapper.bootstrap(rawBootstrap);
1✔
99
          } else {
100
            bootstrapInfo = bootstrapper.bootstrap();
1✔
101
          }
102
          if (bootstrapInfo.servers().isEmpty()) {
1✔
103
            throw new XdsInitializationException("No xDS server provided");
1✔
104
          }
105
          ref = new RefCountedXdsClientObjectPool(bootstrapInfo, target, metricRecorder);
1✔
106
          targetToXdsClientMap.put(target, ref);
1✔
107
        }
108
      }
1✔
109
    }
110
    return ref;
1✔
111
  }
112

113
  @Override
114
  public ImmutableList<String> getTargets() {
115
    return ImmutableList.copyOf(targetToXdsClientMap.keySet());
1✔
116
  }
117

118
  private static class SharedXdsClientPoolProviderHolder {
119
    private static final SharedXdsClientPoolProvider instance = new SharedXdsClientPoolProvider();
1✔
120
  }
121

122
  @ThreadSafe
123
  @VisibleForTesting
124
  class RefCountedXdsClientObjectPool implements ObjectPool<XdsClient> {
125

126
    private final BootstrapInfo bootstrapInfo;
127
    private final String target; // The target associated with the xDS client.
128
    private final MetricRecorder metricRecorder;
129
    private final Object lock = new Object();
1✔
130
    @GuardedBy("lock")
131
    private ScheduledExecutorService scheduler;
132
    @GuardedBy("lock")
133
    private XdsClient xdsClient;
134
    @GuardedBy("lock")
135
    private int refCount;
136
    @GuardedBy("lock")
137
    private XdsClientMetricReporterImpl metricReporter;
138

139
    @VisibleForTesting
140
    RefCountedXdsClientObjectPool(BootstrapInfo bootstrapInfo, String target,
141
        MetricRecorder metricRecorder) {
1✔
142
      this.bootstrapInfo = checkNotNull(bootstrapInfo);
1✔
143
      this.target = target;
1✔
144
      this.metricRecorder = metricRecorder;
1✔
145
    }
1✔
146

147
    @Override
148
    public XdsClient getObject() {
149
      synchronized (lock) {
1✔
150
        if (refCount == 0) {
1✔
151
          if (LOG_XDS_NODE_ID) {
1✔
152
            log.log(Level.INFO, "xDS node ID: {0}", bootstrapInfo.node().getId());
×
153
          }
154
          scheduler = SharedResourceHolder.get(GrpcUtil.TIMER_SERVICE);
1✔
155
          metricReporter = new XdsClientMetricReporterImpl(metricRecorder, target);
1✔
156
          xdsClient = new XdsClientImpl(
1✔
157
              DEFAULT_XDS_TRANSPORT_FACTORY,
158
              bootstrapInfo,
159
              scheduler,
160
              BACKOFF_POLICY_PROVIDER,
1✔
161
              GrpcUtil.STOPWATCH_SUPPLIER,
162
              TimeProvider.SYSTEM_TIME_PROVIDER,
163
              MessagePrinter.INSTANCE,
164
              new TlsContextManagerImpl(bootstrapInfo),
165
              metricReporter);
166
          metricReporter.setXdsClient(xdsClient);
1✔
167
        }
168
        refCount++;
1✔
169
        return xdsClient;
1✔
170
      }
171
    }
172

173
    @Override
174
    public XdsClient returnObject(Object object) {
175
      synchronized (lock) {
1✔
176
        refCount--;
1✔
177
        if (refCount == 0) {
1✔
178
          xdsClient.shutdown();
1✔
179
          xdsClient = null;
1✔
180
          metricReporter.close();
1✔
181
          metricReporter = null;
1✔
182
          targetToXdsClientMap.remove(target);
1✔
183
          scheduler = SharedResourceHolder.release(GrpcUtil.TIMER_SERVICE, scheduler);
1✔
184
        }
185
        return null;
1✔
186
      }
187
    }
188

189
    @VisibleForTesting
190
    @Nullable
191
    XdsClient getXdsClientForTest() {
192
      synchronized (lock) {
1✔
193
        return xdsClient;
1✔
194
      }
195
    }
196

197
    public String getTarget() {
198
      return target;
×
199
    }
200
  }
201

202
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc