1 // Copyright 2024 The gRPC Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/core/lib/channel/metrics.h"
16
17 #include <memory>
18
19 #include "absl/container/flat_hash_map.h"
20 #include "absl/strings/match.h"
21 #include "absl/strings/str_cat.h"
22 #include "absl/strings/str_join.h"
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25
26 #include "test/core/util/fake_stats_plugin.h"
27 #include "test/core/util/test_config.h"
28
29 namespace grpc_core {
30 namespace {
31
32 using experimental::StatsPluginChannelScope;
33
34 class MetricsTest : public ::testing::Test {
35 public:
TearDown()36 void TearDown() override {
37 GlobalInstrumentsRegistryTestPeer::ResetGlobalInstrumentsRegistry();
38 GlobalStatsPluginRegistryTestPeer::ResetGlobalStatsPluginRegistry();
39 }
40 };
41
TEST_F(MetricsTest,UInt64Counter)42 TEST_F(MetricsTest, UInt64Counter) {
43 const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
44 const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
45 "optional_label_key_2"};
46 auto uint64_counter_handle = GlobalInstrumentsRegistry::RegisterUInt64Counter(
47 "uint64_counter", "A simple uint64 counter.", "unit", kLabelKeys,
48 kOptionalLabelKeys, true);
49 constexpr absl::string_view kLabelValues[] = {"label_value_1",
50 "label_value_2"};
51 constexpr absl::string_view kOptionalLabelValues[] = {
52 "optional_label_value_1", "optional_label_value_2"};
53 constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
54 constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
55 constexpr absl::string_view kDomain3To4 = "domain3.domain4";
56 auto plugin1 = MakeStatsPluginForTarget(kDomain1To4);
57 auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
58 auto plugin3 = MakeStatsPluginForTarget(kDomain3To4);
59 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
60 StatsPluginChannelScope(kDomain1To4, ""))
61 .AddCounter(uint64_counter_handle, 1, kLabelValues, kOptionalLabelValues);
62 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
63 StatsPluginChannelScope(kDomain2To4, ""))
64 .AddCounter(uint64_counter_handle, 2, kLabelValues, kOptionalLabelValues);
65 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
66 StatsPluginChannelScope(kDomain3To4, ""))
67 .AddCounter(uint64_counter_handle, 3, kLabelValues, kOptionalLabelValues);
68 EXPECT_THAT(plugin1->GetCounterValue(uint64_counter_handle, kLabelValues,
69 kOptionalLabelValues),
70 ::testing::Optional(1));
71 EXPECT_THAT(plugin2->GetCounterValue(uint64_counter_handle, kLabelValues,
72 kOptionalLabelValues),
73 ::testing::Optional(3));
74 EXPECT_THAT(plugin3->GetCounterValue(uint64_counter_handle, kLabelValues,
75 kOptionalLabelValues),
76 ::testing::Optional(6));
77 }
78
TEST_F(MetricsTest,DoubleCounter)79 TEST_F(MetricsTest, DoubleCounter) {
80 const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
81 const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
82 "optional_label_key_2"};
83 auto double_counter_handle = GlobalInstrumentsRegistry::RegisterDoubleCounter(
84 "double_counter", "A simple double counter.", "unit", kLabelKeys,
85 kOptionalLabelKeys, true);
86 constexpr absl::string_view kLabelValues[] = {"label_value_1",
87 "label_value_2"};
88 constexpr absl::string_view kOptionalLabelValues[] = {
89 "optional_label_value_1", "optional_label_value_2"};
90 constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
91 constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
92 constexpr absl::string_view kDomain3To4 = "domain3.domain4";
93 auto plugin1 = MakeStatsPluginForTarget(kDomain1To4);
94 auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
95 auto plugin3 = MakeStatsPluginForTarget(kDomain3To4);
96 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
97 StatsPluginChannelScope(kDomain1To4, ""))
98 .AddCounter(double_counter_handle, 1.23, kLabelValues,
99 kOptionalLabelValues);
100 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
101 StatsPluginChannelScope(kDomain2To4, ""))
102 .AddCounter(double_counter_handle, 2.34, kLabelValues,
103 kOptionalLabelValues);
104 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
105 StatsPluginChannelScope(kDomain3To4, ""))
106 .AddCounter(double_counter_handle, 3.45, kLabelValues,
107 kOptionalLabelValues);
108 EXPECT_THAT(plugin1->GetCounterValue(double_counter_handle, kLabelValues,
109 kOptionalLabelValues),
110 ::testing::Optional(1.23));
111 EXPECT_THAT(plugin2->GetCounterValue(double_counter_handle, kLabelValues,
112 kOptionalLabelValues),
113 ::testing::Optional(3.57));
114 EXPECT_THAT(plugin3->GetCounterValue(double_counter_handle, kLabelValues,
115 kOptionalLabelValues),
116 ::testing::Optional(7.02));
117 }
118
TEST_F(MetricsTest,UInt64Histogram)119 TEST_F(MetricsTest, UInt64Histogram) {
120 const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
121 const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
122 "optional_label_key_2"};
123 auto uint64_histogram_handle =
124 GlobalInstrumentsRegistry::RegisterUInt64Histogram(
125 "uint64_histogram", "A simple uint64 histogram.", "unit", kLabelKeys,
126 kOptionalLabelKeys, true);
127 constexpr absl::string_view kLabelValues[] = {"label_value_1",
128 "label_value_2"};
129 constexpr absl::string_view kOptionalLabelValues[] = {
130 "optional_label_value_1", "optional_label_value_2"};
131 constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
132 constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
133 constexpr absl::string_view kDomain3To4 = "domain3.domain4";
134 auto plugin1 = MakeStatsPluginForTarget(kDomain1To4);
135 auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
136 auto plugin3 = MakeStatsPluginForTarget(kDomain3To4);
137 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
138 StatsPluginChannelScope(kDomain1To4, ""))
139 .RecordHistogram(uint64_histogram_handle, 1, kLabelValues,
140 kOptionalLabelValues);
141 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
142 StatsPluginChannelScope(kDomain2To4, ""))
143 .RecordHistogram(uint64_histogram_handle, 2, kLabelValues,
144 kOptionalLabelValues);
145 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
146 StatsPluginChannelScope(kDomain3To4, ""))
147 .RecordHistogram(uint64_histogram_handle, 3, kLabelValues,
148 kOptionalLabelValues);
149 EXPECT_THAT(plugin1->GetHistogramValue(uint64_histogram_handle, kLabelValues,
150 kOptionalLabelValues),
151 ::testing::Optional(::testing::UnorderedElementsAre(1)));
152 EXPECT_THAT(plugin2->GetHistogramValue(uint64_histogram_handle, kLabelValues,
153 kOptionalLabelValues),
154 ::testing::Optional(::testing::UnorderedElementsAre(1, 2)));
155 EXPECT_THAT(plugin3->GetHistogramValue(uint64_histogram_handle, kLabelValues,
156 kOptionalLabelValues),
157 ::testing::Optional(::testing::UnorderedElementsAre(1, 2, 3)));
158 }
159
TEST_F(MetricsTest,DoubleHistogram)160 TEST_F(MetricsTest, DoubleHistogram) {
161 const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
162 const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
163 "optional_label_key_2"};
164 auto double_histogram_handle =
165 GlobalInstrumentsRegistry::RegisterDoubleHistogram(
166 "double_histogram", "A simple double histogram.", "unit", kLabelKeys,
167 kOptionalLabelKeys, true);
168 constexpr absl::string_view kLabelValues[] = {"label_value_1",
169 "label_value_2"};
170 constexpr absl::string_view kOptionalLabelValues[] = {
171 "optional_label_value_1", "optional_label_value_2"};
172 constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
173 constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
174 constexpr absl::string_view kDomain3To4 = "domain3.domain4";
175 auto plugin1 = MakeStatsPluginForTarget(kDomain1To4);
176 auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
177 auto plugin3 = MakeStatsPluginForTarget(kDomain3To4);
178 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
179 StatsPluginChannelScope(kDomain1To4, ""))
180 .RecordHistogram(double_histogram_handle, 1.23, kLabelValues,
181 kOptionalLabelValues);
182 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
183 StatsPluginChannelScope(kDomain2To4, ""))
184 .RecordHistogram(double_histogram_handle, 2.34, kLabelValues,
185 kOptionalLabelValues);
186 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
187 StatsPluginChannelScope(kDomain3To4, ""))
188 .RecordHistogram(double_histogram_handle, 3.45, kLabelValues,
189 kOptionalLabelValues);
190 EXPECT_THAT(plugin1->GetHistogramValue(double_histogram_handle, kLabelValues,
191 kOptionalLabelValues),
192 ::testing::Optional(::testing::UnorderedElementsAre(1.23)));
193 EXPECT_THAT(plugin2->GetHistogramValue(double_histogram_handle, kLabelValues,
194 kOptionalLabelValues),
195 ::testing::Optional(::testing::UnorderedElementsAre(1.23, 2.34)));
196 EXPECT_THAT(
197 plugin3->GetHistogramValue(double_histogram_handle, kLabelValues,
198 kOptionalLabelValues),
199 ::testing::Optional(::testing::UnorderedElementsAre(1.23, 2.34, 3.45)));
200 }
201
TEST_F(MetricsTest,Int64Gauge)202 TEST_F(MetricsTest, Int64Gauge) {
203 const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
204 const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
205 "optional_label_key_2"};
206 auto int64_gauge_handle = GlobalInstrumentsRegistry::RegisterInt64Gauge(
207 "int64_gauge", "A simple int64 gauge.", "unit", kLabelKeys,
208 kOptionalLabelKeys, true);
209 constexpr absl::string_view kLabelValues[] = {"label_value_1",
210 "label_value_2"};
211 constexpr absl::string_view kOptionalLabelValues[] = {
212 "optional_label_value_1", "optional_label_value_2"};
213 constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
214 constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
215 constexpr absl::string_view kDomain3To4 = "domain3.domain4";
216 auto plugin1 = MakeStatsPluginForTarget(kDomain1To4);
217 auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
218 auto plugin3 = MakeStatsPluginForTarget(kDomain3To4);
219 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
220 StatsPluginChannelScope(kDomain1To4, ""))
221 .SetGauge(int64_gauge_handle, 1, kLabelValues, kOptionalLabelValues);
222 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
223 StatsPluginChannelScope(kDomain2To4, ""))
224 .SetGauge(int64_gauge_handle, 2, kLabelValues, kOptionalLabelValues);
225 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
226 StatsPluginChannelScope(kDomain3To4, ""))
227 .SetGauge(int64_gauge_handle, 3, kLabelValues, kOptionalLabelValues);
228 EXPECT_THAT(plugin1->GetGaugeValue(int64_gauge_handle, kLabelValues,
229 kOptionalLabelValues),
230 ::testing::Optional(1));
231 EXPECT_THAT(plugin2->GetGaugeValue(int64_gauge_handle, kLabelValues,
232 kOptionalLabelValues),
233 ::testing::Optional(2));
234 EXPECT_THAT(plugin3->GetGaugeValue(int64_gauge_handle, kLabelValues,
235 kOptionalLabelValues),
236 ::testing::Optional(3));
237 }
238
TEST_F(MetricsTest,DoubleGauge)239 TEST_F(MetricsTest, DoubleGauge) {
240 const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
241 const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
242 "optional_label_key_2"};
243 auto double_gauge_handle = GlobalInstrumentsRegistry::RegisterDoubleGauge(
244 "double_gauge", "A simple double gauge.", "unit", kLabelKeys,
245 kOptionalLabelKeys, true);
246 constexpr absl::string_view kLabelValues[] = {"label_value_1",
247 "label_value_2"};
248 constexpr absl::string_view kOptionalLabelValues[] = {
249 "optional_label_value_1", "optional_label_value_2"};
250 constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
251 constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
252 constexpr absl::string_view kDomain3To4 = "domain3.domain4";
253 auto plugin1 = MakeStatsPluginForTarget(kDomain1To4);
254 auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
255 auto plugin3 = MakeStatsPluginForTarget(kDomain3To4);
256 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
257 StatsPluginChannelScope(kDomain1To4, ""))
258 .SetGauge(double_gauge_handle, 1.23, kLabelValues, kOptionalLabelValues);
259 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
260 StatsPluginChannelScope(kDomain2To4, ""))
261 .SetGauge(double_gauge_handle, 2.34, kLabelValues, kOptionalLabelValues);
262 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
263 StatsPluginChannelScope(kDomain3To4, ""))
264 .SetGauge(double_gauge_handle, 3.45, kLabelValues, kOptionalLabelValues);
265 EXPECT_THAT(plugin1->GetGaugeValue(double_gauge_handle, kLabelValues,
266 kOptionalLabelValues),
267 ::testing::Optional(1.23));
268 EXPECT_THAT(plugin2->GetGaugeValue(double_gauge_handle, kLabelValues,
269 kOptionalLabelValues),
270 ::testing::Optional(2.34));
271 EXPECT_THAT(plugin3->GetGaugeValue(double_gauge_handle, kLabelValues,
272 kOptionalLabelValues),
273 ::testing::Optional(3.45));
274 }
275
TEST_F(MetricsTest,Int64CallbackGauge)276 TEST_F(MetricsTest, Int64CallbackGauge) {
277 const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
278 const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
279 "optional_label_key_2"};
280 auto int64_gauge_handle =
281 GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
282 "int64_gauge", "A simple int64 gauge.", "unit", kLabelKeys,
283 kOptionalLabelKeys, true);
284 constexpr absl::string_view kLabelValues[] = {"label_value_1",
285 "label_value_2"};
286 constexpr absl::string_view kLabelValues2[] = {"label_value_3",
287 "label_value_2"};
288 constexpr absl::string_view kOptionalLabelValues[] = {
289 "optional_label_value_1", "optional_label_value_2"};
290 constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
291 constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
292 constexpr absl::string_view kDomain3To4 = "domain3.domain4";
293 auto plugin1 = MakeStatsPluginForTarget(kDomain3To4);
294 auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
295 auto plugin3 = MakeStatsPluginForTarget(kDomain1To4);
296 // Register two callbacks that set the same metric but with different
297 // label values. The callbacks get used only by plugin1.
298 gpr_log(GPR_INFO, "testing callbacks for: plugin1");
299 auto group1 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
300 StatsPluginChannelScope(kDomain3To4, ""));
301 auto callback1 = group1.RegisterCallback(
302 [&](CallbackMetricReporter& reporter) {
303 reporter.Report(int64_gauge_handle, 1, kLabelValues,
304 kOptionalLabelValues);
305 },
306 {int64_gauge_handle});
307 auto callback2 = group1.RegisterCallback(
308 [&](CallbackMetricReporter& reporter) {
309 reporter.Report(int64_gauge_handle, 2, kLabelValues2,
310 kOptionalLabelValues);
311 },
312 {int64_gauge_handle});
313 // No plugins have data yet.
314 EXPECT_EQ(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
315 kOptionalLabelValues),
316 absl::nullopt);
317 EXPECT_EQ(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
318 kOptionalLabelValues),
319 absl::nullopt);
320 EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
321 kOptionalLabelValues),
322 absl::nullopt);
323 EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
324 kOptionalLabelValues),
325 absl::nullopt);
326 EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
327 kOptionalLabelValues),
328 absl::nullopt);
329 EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
330 kOptionalLabelValues),
331 absl::nullopt);
332 // Now invoke the callbacks.
333 plugin1->TriggerCallbacks();
334 plugin2->TriggerCallbacks();
335 plugin3->TriggerCallbacks();
336 // Now plugin1 should have data, but the others should not.
337 EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
338 kOptionalLabelValues),
339 ::testing::Optional(1));
340 EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
341 kOptionalLabelValues),
342 ::testing::Optional(2));
343 EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
344 kOptionalLabelValues),
345 absl::nullopt);
346 EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
347 kOptionalLabelValues),
348 absl::nullopt);
349 EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
350 kOptionalLabelValues),
351 absl::nullopt);
352 EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
353 kOptionalLabelValues),
354 absl::nullopt);
355 // De-register the callbacks.
356 callback1.reset();
357 callback2.reset();
358 // Now register callbacks that hit both plugin1 and plugin2.
359 gpr_log(GPR_INFO, "testing callbacks for: plugin1, plugin2");
360 auto group2 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
361 StatsPluginChannelScope(kDomain2To4, ""));
362 callback1 = group2.RegisterCallback(
363 [&](CallbackMetricReporter& reporter) {
364 reporter.Report(int64_gauge_handle, 3, kLabelValues,
365 kOptionalLabelValues);
366 },
367 {int64_gauge_handle});
368 callback2 = group2.RegisterCallback(
369 [&](CallbackMetricReporter& reporter) {
370 reporter.Report(int64_gauge_handle, 4, kLabelValues2,
371 kOptionalLabelValues);
372 },
373 {int64_gauge_handle});
374 // Plugin1 still has data from before, but the others have none.
375 EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
376 kOptionalLabelValues),
377 ::testing::Optional(1));
378 EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
379 kOptionalLabelValues),
380 ::testing::Optional(2));
381 EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
382 kOptionalLabelValues),
383 absl::nullopt);
384 EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
385 kOptionalLabelValues),
386 absl::nullopt);
387 EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
388 kOptionalLabelValues),
389 absl::nullopt);
390 EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
391 kOptionalLabelValues),
392 absl::nullopt);
393 // Now invoke the callbacks.
394 plugin1->TriggerCallbacks();
395 plugin2->TriggerCallbacks();
396 plugin3->TriggerCallbacks();
397 // Now plugin1 and plugin2 should have data, but plugin3 should not.
398 EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
399 kOptionalLabelValues),
400 ::testing::Optional(3));
401 EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
402 kOptionalLabelValues),
403 ::testing::Optional(4));
404 EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
405 kOptionalLabelValues),
406 ::testing::Optional(3));
407 EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
408 kOptionalLabelValues),
409 ::testing::Optional(4));
410 EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
411 kOptionalLabelValues),
412 absl::nullopt);
413 EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
414 kOptionalLabelValues),
415 absl::nullopt);
416 // De-register the callbacks.
417 callback1.reset();
418 callback2.reset();
419 // Now register callbacks that hit all three plugins.
420 gpr_log(GPR_INFO, "testing callbacks for: plugin1, plugin2, plugin3");
421 auto group3 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
422 StatsPluginChannelScope(kDomain1To4, ""));
423 callback1 = group3.RegisterCallback(
424 [&](CallbackMetricReporter& reporter) {
425 reporter.Report(int64_gauge_handle, 5, kLabelValues,
426 kOptionalLabelValues);
427 },
428 {int64_gauge_handle});
429 callback2 = group3.RegisterCallback(
430 [&](CallbackMetricReporter& reporter) {
431 reporter.Report(int64_gauge_handle, 6, kLabelValues2,
432 kOptionalLabelValues);
433 },
434 {int64_gauge_handle});
435 // Plugin1 and plugin2 still has data from before, but plugin3 has none.
436 EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
437 kOptionalLabelValues),
438 ::testing::Optional(3));
439 EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
440 kOptionalLabelValues),
441 ::testing::Optional(4));
442 EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
443 kOptionalLabelValues),
444 ::testing::Optional(3));
445 EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
446 kOptionalLabelValues),
447 ::testing::Optional(4));
448 EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
449 kOptionalLabelValues),
450 absl::nullopt);
451 EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
452 kOptionalLabelValues),
453 absl::nullopt);
454 // Now invoke the callbacks.
455 plugin1->TriggerCallbacks();
456 plugin2->TriggerCallbacks();
457 plugin3->TriggerCallbacks();
458 // Now plugin1 and plugin2 should have data, but plugin3 should not.
459 EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
460 kOptionalLabelValues),
461 ::testing::Optional(5));
462 EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
463 kOptionalLabelValues),
464 ::testing::Optional(6));
465 EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
466 kOptionalLabelValues),
467 ::testing::Optional(5));
468 EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
469 kOptionalLabelValues),
470 ::testing::Optional(6));
471 EXPECT_THAT(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
472 kOptionalLabelValues),
473 ::testing::Optional(5));
474 EXPECT_THAT(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
475 kOptionalLabelValues),
476 ::testing::Optional(6));
477 // Need to destroy callbacks before the plugin group that created them.
478 callback1.reset();
479 callback2.reset();
480 }
481
TEST_F(MetricsTest,DoubleCallbackGauge)482 TEST_F(MetricsTest, DoubleCallbackGauge) {
483 const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
484 const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
485 "optional_label_key_2"};
486 auto double_gauge_handle =
487 GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
488 "double_gauge", "A simple double gauge.", "unit", kLabelKeys,
489 kOptionalLabelKeys, true);
490 constexpr absl::string_view kLabelValues[] = {"label_value_1",
491 "label_value_2"};
492 constexpr absl::string_view kLabelValues2[] = {"label_value_3",
493 "label_value_2"};
494 constexpr absl::string_view kOptionalLabelValues[] = {
495 "optional_label_value_1", "optional_label_value_2"};
496 constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
497 constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
498 constexpr absl::string_view kDomain3To4 = "domain3.domain4";
499 auto plugin1 = MakeStatsPluginForTarget(kDomain3To4);
500 auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
501 auto plugin3 = MakeStatsPluginForTarget(kDomain1To4);
502 // Register two callbacks that set the same metric but with different
503 // label values. The callbacks get used only by plugin1.
504 gpr_log(GPR_INFO, "testing callbacks for: plugin1");
505 auto group1 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
506 StatsPluginChannelScope(kDomain3To4, ""));
507 auto callback1 = group1.RegisterCallback(
508 [&](CallbackMetricReporter& reporter) {
509 reporter.Report(double_gauge_handle, 1.23, kLabelValues,
510 kOptionalLabelValues);
511 },
512 {double_gauge_handle});
513 auto callback2 = group1.RegisterCallback(
514 [&](CallbackMetricReporter& reporter) {
515 reporter.Report(double_gauge_handle, 2.34, kLabelValues2,
516 kOptionalLabelValues);
517 },
518 {double_gauge_handle});
519 // No plugins have data yet.
520 EXPECT_EQ(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
521 kOptionalLabelValues),
522 absl::nullopt);
523 EXPECT_EQ(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
524 kOptionalLabelValues),
525 absl::nullopt);
526 EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
527 kOptionalLabelValues),
528 absl::nullopt);
529 EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
530 kOptionalLabelValues),
531 absl::nullopt);
532 EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
533 kOptionalLabelValues),
534 absl::nullopt);
535 EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
536 kOptionalLabelValues),
537 absl::nullopt);
538 // Now invoke the callbacks.
539 plugin1->TriggerCallbacks();
540 plugin2->TriggerCallbacks();
541 plugin3->TriggerCallbacks();
542 // Now plugin1 should have data, but the others should not.
543 EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
544 kOptionalLabelValues),
545 ::testing::Optional(1.23));
546 EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
547 kOptionalLabelValues),
548 ::testing::Optional(2.34));
549 EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
550 kOptionalLabelValues),
551 absl::nullopt);
552 EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
553 kOptionalLabelValues),
554 absl::nullopt);
555 EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
556 kOptionalLabelValues),
557 absl::nullopt);
558 EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
559 kOptionalLabelValues),
560 absl::nullopt);
561 // De-register the callbacks.
562 callback1.reset();
563 callback2.reset();
564 // Now register callbacks that hit both plugin1 and plugin2.
565 gpr_log(GPR_INFO, "testing callbacks for: plugin1, plugin2");
566 auto group2 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
567 StatsPluginChannelScope(kDomain2To4, ""));
568 callback1 = group2.RegisterCallback(
569 [&](CallbackMetricReporter& reporter) {
570 reporter.Report(double_gauge_handle, 3.45, kLabelValues,
571 kOptionalLabelValues);
572 },
573 {double_gauge_handle});
574 callback2 = group2.RegisterCallback(
575 [&](CallbackMetricReporter& reporter) {
576 reporter.Report(double_gauge_handle, 4.56, kLabelValues2,
577 kOptionalLabelValues);
578 },
579 {double_gauge_handle});
580 // Plugin1 still has data from before, but the others have none.
581 EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
582 kOptionalLabelValues),
583 ::testing::Optional(1.23));
584 EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
585 kOptionalLabelValues),
586 ::testing::Optional(2.34));
587 EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
588 kOptionalLabelValues),
589 absl::nullopt);
590 EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
591 kOptionalLabelValues),
592 absl::nullopt);
593 EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
594 kOptionalLabelValues),
595 absl::nullopt);
596 EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
597 kOptionalLabelValues),
598 absl::nullopt);
599 // Now invoke the callbacks.
600 plugin1->TriggerCallbacks();
601 plugin2->TriggerCallbacks();
602 plugin3->TriggerCallbacks();
603 // Now plugin1 and plugin2 should have data, but plugin3 should not.
604 EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
605 kOptionalLabelValues),
606 ::testing::Optional(3.45));
607 EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
608 kOptionalLabelValues),
609 ::testing::Optional(4.56));
610 EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
611 kOptionalLabelValues),
612 ::testing::Optional(3.45));
613 EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
614 kOptionalLabelValues),
615 ::testing::Optional(4.56));
616 EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
617 kOptionalLabelValues),
618 absl::nullopt);
619 EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
620 kOptionalLabelValues),
621 absl::nullopt);
622 // De-register the callbacks.
623 callback1.reset();
624 callback2.reset();
625 // Now register callbacks that hit all three plugins.
626 gpr_log(GPR_INFO, "testing callbacks for: plugin1, plugin2, plugin3");
627 auto group3 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
628 StatsPluginChannelScope(kDomain1To4, ""));
629 callback1 = group3.RegisterCallback(
630 [&](CallbackMetricReporter& reporter) {
631 reporter.Report(double_gauge_handle, 5.67, kLabelValues,
632 kOptionalLabelValues);
633 },
634 {double_gauge_handle});
635 callback2 = group3.RegisterCallback(
636 [&](CallbackMetricReporter& reporter) {
637 reporter.Report(double_gauge_handle, 6.78, kLabelValues2,
638 kOptionalLabelValues);
639 },
640 {double_gauge_handle});
641 // Plugin1 and plugin2 still has data from before, but plugin3 has none.
642 EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
643 kOptionalLabelValues),
644 ::testing::Optional(3.45));
645 EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
646 kOptionalLabelValues),
647 ::testing::Optional(4.56));
648 EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
649 kOptionalLabelValues),
650 ::testing::Optional(3.45));
651 EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
652 kOptionalLabelValues),
653 ::testing::Optional(4.56));
654 EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
655 kOptionalLabelValues),
656 absl::nullopt);
657 EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
658 kOptionalLabelValues),
659 absl::nullopt);
660 // Now invoke the callbacks.
661 plugin1->TriggerCallbacks();
662 plugin2->TriggerCallbacks();
663 plugin3->TriggerCallbacks();
664 // Now plugin1 and plugin2 should have data, but plugin3 should not.
665 EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
666 kOptionalLabelValues),
667 ::testing::Optional(5.67));
668 EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
669 kOptionalLabelValues),
670 ::testing::Optional(6.78));
671 EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
672 kOptionalLabelValues),
673 ::testing::Optional(5.67));
674 EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
675 kOptionalLabelValues),
676 ::testing::Optional(6.78));
677 EXPECT_THAT(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
678 kOptionalLabelValues),
679 ::testing::Optional(5.67));
680 EXPECT_THAT(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
681 kOptionalLabelValues),
682 ::testing::Optional(6.78));
683 // Need to destroy callbacks before the plugin group that created them.
684 callback1.reset();
685 callback2.reset();
686 }
687
TEST_F(MetricsTest,DisableByDefaultMetricIsNotRecordedByFakeStatsPlugin)688 TEST_F(MetricsTest, DisableByDefaultMetricIsNotRecordedByFakeStatsPlugin) {
689 const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
690 const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
691 "optional_label_key_2"};
692 auto double_histogram_handle =
693 GlobalInstrumentsRegistry::RegisterDoubleHistogram(
694 "double_histogram", "A simple double histogram.", "unit", kLabelKeys,
695 kOptionalLabelKeys, /*enable_by_default=*/false);
696 constexpr absl::string_view kLabelValues[] = {"label_value_1",
697 "label_value_2"};
698 constexpr absl::string_view kOptionalLabelValues[] = {
699 "optional_label_value_1", "optional_label_value_2"};
700 constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
701 auto plugin = MakeStatsPluginForTarget(kDomain1To4);
702 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
703 StatsPluginChannelScope(kDomain1To4, ""))
704 .RecordHistogram(double_histogram_handle, 1.23, kLabelValues,
705 kOptionalLabelValues);
706 EXPECT_EQ(plugin->GetHistogramValue(double_histogram_handle, kLabelValues,
707 kOptionalLabelValues),
708 absl::nullopt);
709 }
710
711 using MetricsDeathTest = MetricsTest;
712
TEST_F(MetricsDeathTest,RegisterTheSameMetricNameWouldCrash)713 TEST_F(MetricsDeathTest, RegisterTheSameMetricNameWouldCrash) {
714 const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
715 const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
716 "optional_label_key_2"};
717 (void)GlobalInstrumentsRegistry::RegisterDoubleHistogram(
718 "double_histogram", "A simple double histogram.", "unit", kLabelKeys,
719 kOptionalLabelKeys, true);
720 EXPECT_DEATH(GlobalInstrumentsRegistry::RegisterDoubleHistogram(
721 "double_histogram", "A simple double histogram.", "unit",
722 kLabelKeys, kOptionalLabelKeys, true),
723 "Metric name double_histogram has already been registered.");
724 }
725
726 } // namespace
727 } // namespace grpc_core
728
main(int argc,char ** argv)729 int main(int argc, char** argv) {
730 grpc::testing::TestEnvironment env(&argc, argv);
731 ::testing::InitGoogleTest(&argc, argv);
732 int ret = RUN_ALL_TESTS();
733 return ret;
734 }
735