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

grpc / grpc-java / #19211

08 May 2024 10:50PM UTC coverage: 88.309% (-0.02%) from 88.328%
#19211

push

github

ejona86
xds: Plumb locality in xds_cluster_impl and weighted_target

As part of gRFC A78:

> To support the locality label in the WRR metrics, we will extend the
> `weighted_target` LB policy (see A28) to define a resolver attribute
> that indicates the name of its child. This attribute will be passed
> down to each of its children with the appropriate value, so that any
> LB policy that sits underneath the `weighted_target` policy will be
> able to use it.

xds_cluster_impl is involved because it uses the child names in the
AddressFilter, which must match the names used by weighted_target.
Instead of using Locality.toString() in multiple policies and assuming
the policies agree, we now have xds_cluster_impl decide the locality's
name and pass it down explicitly. This allows us to change the name
format to match gRFC A78:

> If locality information is available, the value of this label will be
> of the form `{region="${REGION}", zone="${ZONE}",
> sub_zone="${SUB_ZONE}"}`, where `${REGION}`, `${ZONE}`, and
> `${SUB_ZONE}` are replaced with the actual values. If no locality
> information is available, the label will be set to the empty string.

31515 of 35687 relevant lines covered (88.31%)

0.88 hits per line

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

95.83
/../api/src/main/java/io/grpc/MetricInstrumentRegistry.java
1
/*
2
 * Copyright 2024 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;
18

19
import static com.google.common.base.Preconditions.checkArgument;
20
import static com.google.common.base.Preconditions.checkNotNull;
21

22
import com.google.common.annotations.VisibleForTesting;
23
import com.google.common.base.Strings;
24
import java.util.Arrays;
25
import java.util.Collections;
26
import java.util.HashSet;
27
import java.util.List;
28
import java.util.Set;
29
import javax.annotation.concurrent.GuardedBy;
30

31
/**
32
 * A registry for globally registered metric instruments.
33
 */
34
@Internal
35
public final class MetricInstrumentRegistry {
36
  static final int INITIAL_INSTRUMENT_CAPACITY = 5;
37
  private static MetricInstrumentRegistry instance;
38
  private final Object lock = new Object();
1✔
39
  @GuardedBy("lock")
1✔
40
  private final Set<String> registeredMetricNames = new HashSet<>();
41
  @GuardedBy("lock")
1✔
42
  private MetricInstrument[] metricInstruments =
43
      new MetricInstrument[INITIAL_INSTRUMENT_CAPACITY];
44
  @GuardedBy("lock")
45
  private int nextAvailableMetricIndex;
46

47
  @VisibleForTesting
48
  MetricInstrumentRegistry() {}
1✔
49

50
  /**
51
   * Returns the default metric instrument registry.
52
   */
53
  public static synchronized MetricInstrumentRegistry getDefaultRegistry() {
54
    if (instance == null) {
1✔
55
      instance = new MetricInstrumentRegistry();
1✔
56
    }
57
    return instance;
1✔
58
  }
59

60
  /**
61
   * Returns a list of registered metric instruments.
62
   */
63
  public List<MetricInstrument> getMetricInstruments() {
64
    synchronized (lock) {
1✔
65
      return Collections.unmodifiableList(
1✔
66
          Arrays.asList(Arrays.copyOfRange(metricInstruments, 0, nextAvailableMetricIndex)));
1✔
67
    }
68
  }
69

70
  /**
71
   * Registers a new Double Counter metric instrument.
72
   *
73
   * @param name the name of the metric
74
   * @param description a description of the metric
75
   * @param unit the unit of measurement for the metric
76
   * @param requiredLabelKeys a list of required label keys
77
   * @param optionalLabelKeys a list of optional label keys
78
   * @param enableByDefault whether the metric should be enabled by default
79
   * @return the newly created DoubleCounterMetricInstrument
80
   * @throws IllegalStateException if a metric with the same name already exists
81
   */
82
  public DoubleCounterMetricInstrument registerDoubleCounter(String name,
83
      String description, String unit, List<String> requiredLabelKeys,
84
      List<String> optionalLabelKeys, boolean enableByDefault) {
85
    checkArgument(!Strings.isNullOrEmpty(name), "missing metric name");
1✔
86
    checkNotNull(description, "description");
1✔
87
    checkNotNull(unit, "unit");
1✔
88
    checkNotNull(requiredLabelKeys, "requiredLabelKeys");
1✔
89
    checkNotNull(optionalLabelKeys, "optionalLabelKeys");
1✔
90
    synchronized (lock) {
1✔
91
      if (registeredMetricNames.contains(name)) {
1✔
92
        throw new IllegalStateException("Metric with name " + name + " already exists");
1✔
93
      }
94
      int index = nextAvailableMetricIndex;
1✔
95
      if (index + 1 == metricInstruments.length) {
1✔
96
        resizeMetricInstruments();
×
97
      }
98
      // TODO(dnvindhya): add limit for number of optional labels allowed
99
      DoubleCounterMetricInstrument instrument = new DoubleCounterMetricInstrument(
1✔
100
          index, name, description, unit, requiredLabelKeys, optionalLabelKeys,
101
          enableByDefault);
102
      metricInstruments[index] = instrument;
1✔
103
      registeredMetricNames.add(name);
1✔
104
      nextAvailableMetricIndex += 1;
1✔
105
      return instrument;
1✔
106
    }
107
  }
108

109
  /**
110
   * Registers a new Long Counter metric instrument.
111
   *
112
   * @param name the name of the metric
113
   * @param description a description of the metric
114
   * @param unit the unit of measurement for the metric
115
   * @param requiredLabelKeys a list of required label keys
116
   * @param optionalLabelKeys a list of optional label keys
117
   * @param enableByDefault whether the metric should be enabled by default
118
   * @return the newly created LongCounterMetricInstrument
119
   * @throws IllegalStateException if a metric with the same name already exists
120
   */
121
  public LongCounterMetricInstrument registerLongCounter(String name,
122
      String description, String unit, List<String> requiredLabelKeys,
123
      List<String> optionalLabelKeys, boolean enableByDefault) {
124
    checkArgument(!Strings.isNullOrEmpty(name), "missing metric name");
1✔
125
    checkNotNull(description, "description");
1✔
126
    checkNotNull(unit, "unit");
1✔
127
    checkNotNull(requiredLabelKeys, "requiredLabelKeys");
1✔
128
    checkNotNull(optionalLabelKeys, "optionalLabelKeys");
1✔
129
    synchronized (lock) {
1✔
130
      if (registeredMetricNames.contains(name)) {
1✔
131
        throw new IllegalStateException("Metric with name " + name + " already exists");
1✔
132
      }
133
      int index = nextAvailableMetricIndex;
1✔
134
      if (index + 1 == metricInstruments.length) {
1✔
135
        resizeMetricInstruments();
×
136
      }
137
      LongCounterMetricInstrument instrument = new LongCounterMetricInstrument(
1✔
138
          index, name, description, unit, requiredLabelKeys, optionalLabelKeys,
139
          enableByDefault);
140
      metricInstruments[index] = instrument;
1✔
141
      registeredMetricNames.add(name);
1✔
142
      nextAvailableMetricIndex += 1;
1✔
143
      return instrument;
1✔
144
    }
145
  }
146

147
  /**
148
   * Registers a new Double Histogram metric instrument.
149
   *
150
   * @param name the name of the metric
151
   * @param description a description of the metric
152
   * @param unit the unit of measurement for the metric
153
   * @param bucketBoundaries recommended set of explicit bucket boundaries for the histogram
154
   * @param requiredLabelKeys a list of required label keys
155
   * @param optionalLabelKeys a list of optional label keys
156
   * @param enableByDefault whether the metric should be enabled by default
157
   * @return the newly created DoubleHistogramMetricInstrument
158
   * @throws IllegalStateException if a metric with the same name already exists
159
   */
160
  public DoubleHistogramMetricInstrument registerDoubleHistogram(String name,
161
      String description, String unit, List<Double> bucketBoundaries,
162
      List<String> requiredLabelKeys, List<String> optionalLabelKeys, boolean enableByDefault) {
163
    checkArgument(!Strings.isNullOrEmpty(name), "missing metric name");
1✔
164
    checkNotNull(description, "description");
1✔
165
    checkNotNull(unit, "unit");
1✔
166
    checkNotNull(bucketBoundaries, "bucketBoundaries");
1✔
167
    checkNotNull(requiredLabelKeys, "requiredLabelKeys");
1✔
168
    checkNotNull(optionalLabelKeys, "optionalLabelKeys");
1✔
169
    synchronized (lock) {
1✔
170
      if (registeredMetricNames.contains(name)) {
1✔
171
        throw new IllegalStateException("Metric with name " + name + " already exists");
1✔
172
      }
173
      int index = nextAvailableMetricIndex;
1✔
174
      if (index + 1 == metricInstruments.length) {
1✔
175
        resizeMetricInstruments();
×
176
      }
177
      DoubleHistogramMetricInstrument instrument = new DoubleHistogramMetricInstrument(
1✔
178
          index, name, description, unit, bucketBoundaries, requiredLabelKeys,
179
          optionalLabelKeys,
180
          enableByDefault);
181
      metricInstruments[index] = instrument;
1✔
182
      registeredMetricNames.add(name);
1✔
183
      nextAvailableMetricIndex += 1;
1✔
184
      return instrument;
1✔
185
    }
186
  }
187

188
  /**
189
   * Registers a new Long Histogram metric instrument.
190
   *
191
   * @param name the name of the metric
192
   * @param description a description of the metric
193
   * @param unit the unit of measurement for the metric
194
   * @param bucketBoundaries recommended set of explicit bucket boundaries for the histogram
195
   * @param requiredLabelKeys a list of required label keys
196
   * @param optionalLabelKeys a list of optional label keys
197
   * @param enableByDefault whether the metric should be enabled by default
198
   * @return the newly created LongHistogramMetricInstrument
199
   * @throws IllegalStateException if a metric with the same name already exists
200
   */
201
  public LongHistogramMetricInstrument registerLongHistogram(String name,
202
      String description, String unit, List<Long> bucketBoundaries, List<String> requiredLabelKeys,
203
      List<String> optionalLabelKeys, boolean enableByDefault) {
204
    checkArgument(!Strings.isNullOrEmpty(name), "missing metric name");
1✔
205
    checkNotNull(description, "description");
1✔
206
    checkNotNull(unit, "unit");
1✔
207
    checkNotNull(bucketBoundaries, "bucketBoundaries");
1✔
208
    checkNotNull(requiredLabelKeys, "requiredLabelKeys");
1✔
209
    checkNotNull(optionalLabelKeys, "optionalLabelKeys");
1✔
210
    synchronized (lock) {
1✔
211
      if (registeredMetricNames.contains(name)) {
1✔
212
        throw new IllegalStateException("Metric with name " + name + " already exists");
1✔
213
      }
214
      int index = nextAvailableMetricIndex;
1✔
215
      if (index + 1 == metricInstruments.length) {
1✔
216
        resizeMetricInstruments();
1✔
217
      }
218
      LongHistogramMetricInstrument instrument = new LongHistogramMetricInstrument(
1✔
219
          index, name, description, unit, bucketBoundaries, requiredLabelKeys,
220
          optionalLabelKeys,
221
          enableByDefault);
222
      metricInstruments[index] = instrument;
1✔
223
      registeredMetricNames.add(name);
1✔
224
      nextAvailableMetricIndex += 1;
1✔
225
      return instrument;
1✔
226
    }
227
  }
228

229

230
  /**
231
   * Registers a new Long Gauge metric instrument.
232
   *
233
   * @param name the name of the metric
234
   * @param description a description of the metric
235
   * @param unit the unit of measurement for the metric
236
   * @param requiredLabelKeys a list of required label keys
237
   * @param optionalLabelKeys a list of optional label keys
238
   * @param enableByDefault whether the metric should be enabled by default
239
   * @return the newly created LongGaugeMetricInstrument
240
   * @throws IllegalStateException if a metric with the same name already exists
241
   */
242
  public LongGaugeMetricInstrument registerLongGauge(String name, String description,
243
      String unit, List<String> requiredLabelKeys, List<String> optionalLabelKeys, boolean
244
      enableByDefault) {
245
    checkArgument(!Strings.isNullOrEmpty(name), "missing metric name");
1✔
246
    checkNotNull(description, "description");
1✔
247
    checkNotNull(unit, "unit");
1✔
248
    checkNotNull(requiredLabelKeys, "requiredLabelKeys");
1✔
249
    checkNotNull(optionalLabelKeys, "optionalLabelKeys");
1✔
250
    synchronized (lock) {
1✔
251
      if (registeredMetricNames.contains(name)) {
1✔
252
        throw new IllegalStateException("Metric with name " + name + " already exists");
1✔
253
      }
254
      int index = nextAvailableMetricIndex;
1✔
255
      if (index + 1 == metricInstruments.length) {
1✔
256
        resizeMetricInstruments();
×
257
      }
258
      LongGaugeMetricInstrument instrument = new LongGaugeMetricInstrument(
1✔
259
          index, name, description, unit, requiredLabelKeys, optionalLabelKeys,
260
          enableByDefault);
261
      metricInstruments[index] = instrument;
1✔
262
      registeredMetricNames.add(name);
1✔
263
      nextAvailableMetricIndex += 1;
1✔
264
      return instrument;
1✔
265
    }
266
  }
267

268
  @GuardedBy("lock")
269
  private void resizeMetricInstruments() {
270
    // Increase the capacity of the metricInstruments array by INITIAL_INSTRUMENT_CAPACITY
271
    int newInstrumentsCapacity = metricInstruments.length + INITIAL_INSTRUMENT_CAPACITY;
1✔
272
    MetricInstrument[] resizedMetricInstruments = Arrays.copyOf(metricInstruments,
1✔
273
        newInstrumentsCapacity);
274
    metricInstruments = resizedMetricInstruments;
1✔
275
  }
1✔
276
}
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