xref: /aosp_15_r20/external/grpc-grpc/test/cpp/ext/otel/otel_plugin_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 //
2 //
3 // Copyright 2023 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/cpp/ext/otel/otel_plugin.h"
20 
21 #include <atomic>
22 #include <chrono>
23 #include <ratio>
24 #include <type_traits>
25 
26 #include "absl/functional/any_invocable.h"
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include "opentelemetry/common/timestamp.h"
30 #include "opentelemetry/metrics/provider.h"
31 #include "opentelemetry/nostd/variant.h"
32 #include "opentelemetry/sdk/common/attribute_utils.h"
33 #include "opentelemetry/sdk/metrics/data/point_data.h"
34 #include "opentelemetry/sdk/metrics/meter_provider.h"
35 #include "opentelemetry/sdk/metrics/metric_reader.h"
36 
37 #include <grpcpp/ext/otel_plugin.h>
38 #include <grpcpp/grpcpp.h>
39 
40 #include "src/core/lib/channel/call_tracer.h"
41 #include "src/core/lib/config/core_configuration.h"
42 #include "test/core/util/test_config.h"
43 #include "test/cpp/end2end/test_service_impl.h"
44 #include "test/cpp/ext/otel/otel_test_library.h"
45 
46 namespace grpc {
47 namespace testing {
48 namespace {
49 
50 #define GRPC_ARG_SERVER_SELECTOR_KEY "grpc.testing.server_selector_key"
51 #define GRPC_ARG_SERVER_SELECTOR_VALUE "grpc.testing.server_selector_value"
52 
53 template <typename T>
PopulateLabelMap(T label_keys,T label_values,std::unordered_map<std::string,opentelemetry::sdk::common::OwnedAttributeValue> * label_maps)54 void PopulateLabelMap(
55     T label_keys, T label_values,
56     std::unordered_map<std::string,
57                        opentelemetry::sdk::common::OwnedAttributeValue>*
58         label_maps) {
59   for (size_t i = 0; i < label_keys.size(); ++i) {
60     (*label_maps)[std::string(label_keys[i])] = std::string(label_values[i]);
61   }
62 }
63 
64 MATCHER_P4(AttributesEq, label_keys, label_values, optional_label_keys,
65            optional_label_values, "") {
66   std::unordered_map<std::string,
67                      opentelemetry::sdk::common::OwnedAttributeValue>
68       label_map;
69   PopulateLabelMap(label_keys, label_values, &label_map);
70   PopulateLabelMap(optional_label_keys, optional_label_values, &label_map);
71   return ::testing::ExplainMatchResult(
72       ::testing::UnorderedElementsAreArray(label_map),
73       arg.attributes.GetAttributes(), result_listener);
74 }
75 
76 template <typename T>
77 struct Extract;
78 
79 template <template <typename> class T, typename U>
80 struct Extract<const T<U>> {
81   using Type = U;
82 };
83 
84 MATCHER_P(CounterResultEq, value_matcher, "") {
85   return ::testing::ExplainMatchResult(
86       ::testing::VariantWith<opentelemetry::sdk::metrics::SumPointData>(
87           ::testing::Field(&opentelemetry::sdk::metrics::SumPointData::value_,
88                            ::testing::VariantWith<
89                                typename Extract<decltype(value_matcher)>::Type>(
90                                value_matcher))),
91       arg.point_data, result_listener);
92 }
93 
94 MATCHER_P4(HistogramResultEq, sum_matcher, min_matcher, max_matcher, count,
95            "") {
96   return ::testing::ExplainMatchResult(
97       ::testing::VariantWith<
98           opentelemetry::sdk::metrics::HistogramPointData>(::testing::AllOf(
99           ::testing::Field(
100               &opentelemetry::sdk::metrics::HistogramPointData::sum_,
101               ::testing::VariantWith<
102                   typename Extract<decltype(sum_matcher)>::Type>(sum_matcher)),
103           ::testing::Field(
104               &opentelemetry::sdk::metrics::HistogramPointData::min_,
105               ::testing::VariantWith<
106                   typename Extract<decltype(min_matcher)>::Type>(min_matcher)),
107           ::testing::Field(
108               &opentelemetry::sdk::metrics::HistogramPointData::max_,
109               ::testing::VariantWith<
110                   typename Extract<decltype(max_matcher)>::Type>(max_matcher)),
111           ::testing::Field(
112               &opentelemetry::sdk::metrics::HistogramPointData::count_,
113               ::testing::Eq(count)))),
114       arg.point_data, result_listener);
115 }
116 
117 MATCHER_P(GaugeResultIs, value_matcher, "") {
118   return ::testing::ExplainMatchResult(
119       ::testing::VariantWith<opentelemetry::sdk::metrics::LastValuePointData>(
120           ::testing::AllOf(
121               ::testing::Field(
122                   &opentelemetry::sdk::metrics::LastValuePointData::value_,
123                   ::testing::VariantWith<
124                       typename Extract<decltype(value_matcher)>::Type>(
125                       value_matcher)),
126               ::testing::Field(&opentelemetry::sdk::metrics::
127                                    LastValuePointData::is_lastvalue_valid_,
128                                ::testing::IsTrue()))),
129       arg.point_data, result_listener);
130 }
131 
132 // This check might subject to system clock adjustment.
133 MATCHER_P(GaugeResultLaterThan, prev_timestamp, "") {
134   return ::testing::ExplainMatchResult(
135       ::testing::VariantWith<opentelemetry::sdk::metrics::LastValuePointData>(
136           ::testing::Field(
137               &opentelemetry::sdk::metrics::LastValuePointData::sample_ts_,
138               ::testing::Property(
139                   &opentelemetry::common::SystemTimestamp::time_since_epoch,
140                   ::testing::Gt(prev_timestamp.time_since_epoch())))),
141       arg.point_data, result_listener);
142 }
143 
144 MATCHER_P7(GaugeDataIsIncrementalForSpecificMetricAndLabelSet, metric_name,
145            label_key, label_value, optional_label_key, optional_label_value,
146            default_value, greater_than, "") {
147   std::unordered_map<std::string,
148                      opentelemetry::sdk::common::OwnedAttributeValue>
149       label_map;
150   PopulateLabelMap(label_key, label_value, &label_map);
151   PopulateLabelMap(optional_label_key, optional_label_value, &label_map);
152   opentelemetry::common::SystemTimestamp prev_timestamp;
153   auto prev_value = default_value;
154   size_t prev_index = 0;
155   auto& data = arg.at(metric_name);
156   bool result = true;
157   for (size_t i = 1; i < data.size(); ++i) {
158     if (::testing::Matches(::testing::UnorderedElementsAreArray(
159             data[i - 1].attributes.GetAttributes()))(label_map)) {
160       // Update the previous value for the same associated label values.
161       prev_value = opentelemetry::nostd::get<decltype(prev_value)>(
162           opentelemetry::nostd::get<
163               opentelemetry::sdk::metrics::LastValuePointData>(
164               data[i - 1].point_data)
165               .value_);
166       prev_index = i - 1;
167       prev_timestamp = opentelemetry::nostd::get<
168                            opentelemetry::sdk::metrics::LastValuePointData>(
169                            data[i - 1].point_data)
170                            .sample_ts_;
171     }
172     if (!::testing::Matches(::testing::UnorderedElementsAreArray(
173             data[i].attributes.GetAttributes()))(label_map)) {
174       // Skip values that do not have the same associated label values.
175       continue;
176     }
177     *result_listener << " Comparing data[" << i << "] with data[" << prev_index
178                      << "] ";
179     if (greater_than) {
180       result &= ::testing::ExplainMatchResult(
181           ::testing::AllOf(
182               AttributesEq(label_key, label_value, optional_label_key,
183                            optional_label_value),
184               GaugeResultIs(::testing::Gt(prev_value)),
185               GaugeResultLaterThan(prev_timestamp)),
186           data[i], result_listener);
187     } else {
188       result &= ::testing::ExplainMatchResult(
189           ::testing::AllOf(
190               AttributesEq(label_key, label_value, optional_label_key,
191                            optional_label_value),
192               GaugeResultIs(::testing::Ge(prev_value)),
193               GaugeResultLaterThan(prev_timestamp)),
194           data[i], result_listener);
195     }
196   }
197   return result;
198 }
199 
TEST(OpenTelemetryPluginBuildTest,ApiDependency)200 TEST(OpenTelemetryPluginBuildTest, ApiDependency) {
201   opentelemetry::metrics::Provider::GetMeterProvider();
202 }
203 
TEST(OpenTelemetryPluginBuildTest,SdkDependency)204 TEST(OpenTelemetryPluginBuildTest, SdkDependency) {
205   opentelemetry::sdk::metrics::MeterProvider();
206 }
207 
TEST(OpenTelemetryPluginBuildTest,Basic)208 TEST(OpenTelemetryPluginBuildTest, Basic) {
209   grpc::OpenTelemetryPluginBuilder builder;
210 }
211 
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptStarted)212 TEST_F(OpenTelemetryPluginEnd2EndTest, ClientAttemptStarted) {
213   Init(std::move(
214       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
215                                       kClientAttemptStartedInstrumentName})));
216   SendRPC();
217   const char* kMetricName = "grpc.client.attempt.started";
218   auto data = ReadCurrentMetricsData(
219       [&](const absl::flat_hash_map<
220           std::string,
221           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
222               data) { return !data.contains(kMetricName); });
223   ASSERT_EQ(data[kMetricName].size(), 1);
224   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
225       &data[kMetricName][0].point_data);
226   ASSERT_NE(point_data, nullptr);
227   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
228   ASSERT_NE(client_started_value, nullptr);
229   EXPECT_EQ(*client_started_value, 1);
230   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
231   EXPECT_EQ(attributes.size(), 2);
232   const auto* method_value =
233       absl::get_if<std::string>(&attributes.at("grpc.method"));
234   ASSERT_NE(method_value, nullptr);
235   EXPECT_EQ(*method_value, kMethodName);
236   const auto* target_value =
237       absl::get_if<std::string>(&attributes.at("grpc.target"));
238   ASSERT_NE(target_value, nullptr);
239   EXPECT_EQ(*target_value, canonical_server_address_);
240 }
241 
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptDuration)242 TEST_F(OpenTelemetryPluginEnd2EndTest, ClientAttemptDuration) {
243   Init(std::move(
244       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
245                                       kClientAttemptDurationInstrumentName})));
246   SendRPC();
247   const char* kMetricName = "grpc.client.attempt.duration";
248   auto data = ReadCurrentMetricsData(
249       [&](const absl::flat_hash_map<
250           std::string,
251           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
252               data) { return !data.contains(kMetricName); });
253   ASSERT_EQ(data[kMetricName].size(), 1);
254   auto point_data =
255       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
256           &data[kMetricName][0].point_data);
257   ASSERT_NE(point_data, nullptr);
258   ASSERT_EQ(point_data->count_, 1);
259   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
260   EXPECT_EQ(attributes.size(), 3);
261   const auto* method_value =
262       absl::get_if<std::string>(&attributes.at("grpc.method"));
263   ASSERT_NE(method_value, nullptr);
264   EXPECT_EQ(*method_value, kMethodName);
265   const auto* target_value =
266       absl::get_if<std::string>(&attributes.at("grpc.target"));
267   ASSERT_NE(target_value, nullptr);
268   EXPECT_EQ(*target_value, canonical_server_address_);
269   const auto* status_value =
270       absl::get_if<std::string>(&attributes.at("grpc.status"));
271   ASSERT_NE(status_value, nullptr);
272   EXPECT_EQ(*status_value, "OK");
273 }
274 
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptSentTotalCompressedMessageSize)275 TEST_F(OpenTelemetryPluginEnd2EndTest,
276        ClientAttemptSentTotalCompressedMessageSize) {
277   Init(std::move(Options().set_metric_names(
278       {grpc::OpenTelemetryPluginBuilder::
279            kClientAttemptSentTotalCompressedMessageSizeInstrumentName})));
280   SendRPC();
281   const char* kMetricName =
282       "grpc.client.attempt.sent_total_compressed_message_size";
283   auto data = ReadCurrentMetricsData(
284       [&](const absl::flat_hash_map<
285           std::string,
286           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
287               data) { return !data.contains(kMetricName); });
288   ASSERT_EQ(data[kMetricName].size(), 1);
289   auto point_data =
290       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
291           &data[kMetricName][0].point_data);
292   ASSERT_NE(point_data, nullptr);
293   ASSERT_EQ(point_data->count_, 1);
294   ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
295   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
296   EXPECT_EQ(attributes.size(), 3);
297   const auto* method_value =
298       absl::get_if<std::string>(&attributes.at("grpc.method"));
299   ASSERT_NE(method_value, nullptr);
300   EXPECT_EQ(*method_value, kMethodName);
301   const auto* target_value =
302       absl::get_if<std::string>(&attributes.at("grpc.target"));
303   ASSERT_NE(target_value, nullptr);
304   EXPECT_EQ(*target_value, canonical_server_address_);
305   const auto* status_value =
306       absl::get_if<std::string>(&attributes.at("grpc.status"));
307   ASSERT_NE(status_value, nullptr);
308   EXPECT_EQ(*status_value, "OK");
309 }
310 
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptRcvdTotalCompressedMessageSize)311 TEST_F(OpenTelemetryPluginEnd2EndTest,
312        ClientAttemptRcvdTotalCompressedMessageSize) {
313   Init(std::move(Options().set_metric_names(
314       {grpc::OpenTelemetryPluginBuilder::
315            kClientAttemptRcvdTotalCompressedMessageSizeInstrumentName})));
316   SendRPC();
317   const char* kMetricName =
318       "grpc.client.attempt.rcvd_total_compressed_message_size";
319   auto data = ReadCurrentMetricsData(
320       [&](const absl::flat_hash_map<
321           std::string,
322           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
323               data) { return !data.contains(kMetricName); });
324   ASSERT_EQ(data[kMetricName].size(), 1);
325   auto point_data =
326       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
327           &data[kMetricName][0].point_data);
328   ASSERT_NE(point_data, nullptr);
329   ASSERT_EQ(point_data->count_, 1);
330   ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
331   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
332   EXPECT_EQ(attributes.size(), 3);
333   const auto* method_value =
334       absl::get_if<std::string>(&attributes.at("grpc.method"));
335   ASSERT_NE(method_value, nullptr);
336   EXPECT_EQ(*method_value, kMethodName);
337   const auto* target_value =
338       absl::get_if<std::string>(&attributes.at("grpc.target"));
339   ASSERT_NE(target_value, nullptr);
340   EXPECT_EQ(*target_value, canonical_server_address_);
341   const auto* status_value =
342       absl::get_if<std::string>(&attributes.at("grpc.status"));
343   ASSERT_NE(status_value, nullptr);
344   EXPECT_EQ(*status_value, "OK");
345 }
346 
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallStarted)347 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerCallStarted) {
348   Init(std::move(Options().set_metric_names(
349       {grpc::OpenTelemetryPluginBuilder::kServerCallStartedInstrumentName})));
350   SendRPC();
351   const char* kMetricName = "grpc.server.call.started";
352   auto data = ReadCurrentMetricsData(
353       [&](const absl::flat_hash_map<
354           std::string,
355           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
356               data) { return !data.contains(kMetricName); });
357   ASSERT_EQ(data[kMetricName].size(), 1);
358   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
359       &data[kMetricName][0].point_data);
360   ASSERT_NE(point_data, nullptr);
361   auto server_started_value = absl::get_if<int64_t>(&point_data->value_);
362   ASSERT_NE(server_started_value, nullptr);
363   ASSERT_EQ(*server_started_value, 1);
364   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
365   EXPECT_EQ(attributes.size(), 1);
366   const auto* method_value =
367       absl::get_if<std::string>(&attributes.at("grpc.method"));
368   ASSERT_NE(method_value, nullptr);
369   EXPECT_EQ(*method_value, kMethodName);
370 }
371 
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallDuration)372 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerCallDuration) {
373   Init(std::move(Options().set_metric_names(
374       {grpc::OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName})));
375   SendRPC();
376   const char* kMetricName = "grpc.server.call.duration";
377   auto data = ReadCurrentMetricsData(
378       [&](const absl::flat_hash_map<
379           std::string,
380           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
381               data) { return !data.contains(kMetricName); });
382   ASSERT_EQ(data[kMetricName].size(), 1);
383   auto point_data =
384       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
385           &data[kMetricName][0].point_data);
386   ASSERT_NE(point_data, nullptr);
387   ASSERT_EQ(point_data->count_, 1);
388   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
389   EXPECT_EQ(attributes.size(), 2);
390   const auto* method_value =
391       absl::get_if<std::string>(&attributes.at("grpc.method"));
392   ASSERT_NE(method_value, nullptr);
393   EXPECT_EQ(*method_value, kMethodName);
394   const auto* status_value =
395       absl::get_if<std::string>(&attributes.at("grpc.status"));
396   ASSERT_NE(status_value, nullptr);
397   EXPECT_EQ(*status_value, "OK");
398 }
399 
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallSentTotalCompressedMessageSize)400 TEST_F(OpenTelemetryPluginEnd2EndTest,
401        ServerCallSentTotalCompressedMessageSize) {
402   Init(std::move(Options().set_metric_names(
403       {grpc::OpenTelemetryPluginBuilder::
404            kServerCallSentTotalCompressedMessageSizeInstrumentName})));
405   SendRPC();
406   const char* kMetricName =
407       "grpc.server.call.sent_total_compressed_message_size";
408   auto data = ReadCurrentMetricsData(
409       [&](const absl::flat_hash_map<
410           std::string,
411           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
412               data) { return !data.contains(kMetricName); });
413   ASSERT_EQ(data[kMetricName].size(), 1);
414   auto point_data =
415       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
416           &data[kMetricName][0].point_data);
417   ASSERT_NE(point_data, nullptr);
418   EXPECT_EQ(point_data->count_, 1);
419   ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
420   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
421   EXPECT_EQ(attributes.size(), 2);
422   const auto* method_value =
423       absl::get_if<std::string>(&attributes.at("grpc.method"));
424   ASSERT_NE(method_value, nullptr);
425   EXPECT_EQ(*method_value, kMethodName);
426   const auto* status_value =
427       absl::get_if<std::string>(&attributes.at("grpc.status"));
428   ASSERT_NE(status_value, nullptr);
429   EXPECT_EQ(*status_value, "OK");
430 }
431 
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallRcvdTotalCompressedMessageSize)432 TEST_F(OpenTelemetryPluginEnd2EndTest,
433        ServerCallRcvdTotalCompressedMessageSize) {
434   Init(std::move(Options().set_metric_names(
435       {grpc::OpenTelemetryPluginBuilder::
436            kServerCallRcvdTotalCompressedMessageSizeInstrumentName})));
437   SendRPC();
438   const char* kMetricName =
439       "grpc.server.call.rcvd_total_compressed_message_size";
440   auto data = ReadCurrentMetricsData(
441       [&](const absl::flat_hash_map<
442           std::string,
443           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
444               data) { return !data.contains(kMetricName); });
445   ASSERT_EQ(data[kMetricName].size(), 1);
446   auto point_data =
447       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
448           &data[kMetricName][0].point_data);
449   ASSERT_NE(point_data, nullptr);
450   ASSERT_EQ(point_data->count_, 1);
451   ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
452   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
453   EXPECT_EQ(attributes.size(), 2);
454   const auto* method_value =
455       absl::get_if<std::string>(&attributes.at("grpc.method"));
456   ASSERT_NE(method_value, nullptr);
457   EXPECT_EQ(*method_value, kMethodName);
458   const auto* status_value =
459       absl::get_if<std::string>(&attributes.at("grpc.status"));
460   ASSERT_NE(status_value, nullptr);
461   EXPECT_EQ(*status_value, "OK");
462 }
463 
464 // Make sure that no meter provider results in normal operations.
TEST_F(OpenTelemetryPluginEnd2EndTest,NoMeterProviderRegistered)465 TEST_F(OpenTelemetryPluginEnd2EndTest, NoMeterProviderRegistered) {
466   Init(
467       std::move(Options()
468                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
469                                            kClientAttemptStartedInstrumentName})
470                     .set_use_meter_provider(false)));
471   SendRPC();
472 }
473 
474 // Test that the otel plugin sees the expected channel target and default
475 // authority.
TEST_F(OpenTelemetryPluginEnd2EndTest,VerifyChannelScopeTargetAndAuthority)476 TEST_F(OpenTelemetryPluginEnd2EndTest, VerifyChannelScopeTargetAndAuthority) {
477   Init(std::move(
478       Options()
479           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
480                                  kClientAttemptStartedInstrumentName})
481           .set_channel_scope_filter(
482               [&](const OpenTelemetryPluginBuilder::ChannelScope& scope) {
483                 return scope.target() == canonical_server_address_ &&
484                        scope.default_authority() == server_address_;
485               })));
486   SendRPC();
487   const char* kMetricName = "grpc.client.attempt.started";
488   auto data = ReadCurrentMetricsData(
489       [&](const absl::flat_hash_map<
490           std::string,
491           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
492               data) { return !data.contains(kMetricName); });
493   ASSERT_EQ(data[kMetricName].size(), 1);
494 }
495 
496 // Test that a channel scope filter returning true records metrics on the
497 // channel.
TEST_F(OpenTelemetryPluginEnd2EndTest,ChannelScopeFilterReturnsTrue)498 TEST_F(OpenTelemetryPluginEnd2EndTest, ChannelScopeFilterReturnsTrue) {
499   Init(std::move(
500       Options()
501           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
502                                  kClientAttemptStartedInstrumentName})
503           .set_channel_scope_filter(
504               [](const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) {
505                 return true;
506               })));
507   SendRPC();
508   const char* kMetricName = "grpc.client.attempt.started";
509   auto data = ReadCurrentMetricsData(
510       [&](const absl::flat_hash_map<
511           std::string,
512           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
513               data) { return !data.contains(kMetricName); });
514   ASSERT_EQ(data[kMetricName].size(), 1);
515   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
516       &data[kMetricName][0].point_data);
517   ASSERT_NE(point_data, nullptr);
518   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
519   ASSERT_NE(client_started_value, nullptr);
520   EXPECT_EQ(*client_started_value, 1);
521   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
522   EXPECT_EQ(attributes.size(), 2);
523   const auto* method_value =
524       absl::get_if<std::string>(&attributes.at("grpc.method"));
525   ASSERT_NE(method_value, nullptr);
526   EXPECT_EQ(*method_value, kMethodName);
527   const auto* target_value =
528       absl::get_if<std::string>(&attributes.at("grpc.target"));
529   ASSERT_NE(target_value, nullptr);
530   EXPECT_EQ(*target_value, canonical_server_address_);
531 }
532 
533 // Test that a channel scope filter returning false does not record metrics on
534 // the channel.
TEST_F(OpenTelemetryPluginEnd2EndTest,ChannelScopeFilterReturnsFalse)535 TEST_F(OpenTelemetryPluginEnd2EndTest, ChannelScopeFilterReturnsFalse) {
536   Init(std::move(
537       Options()
538           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
539                                  kClientAttemptStartedInstrumentName})
540           .set_channel_scope_filter(
541               [](const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) {
542                 return false;
543               })));
544   SendRPC();
545   auto data = ReadCurrentMetricsData(
546       [&](const absl::flat_hash_map<
547           std::string,
548           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
549           /*data*/) { return false; });
550   ASSERT_TRUE(data.empty());
551 }
552 
553 // Test that a server selector returning true records metrics on the server.
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerSelectorReturnsTrue)554 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerSelectorReturnsTrue) {
555   Init(std::move(Options()
556                      .set_metric_names({grpc::OpenTelemetryPluginBuilder::
557                                             kServerCallDurationInstrumentName})
558                      .set_server_selector(
559                          [](const grpc_core::ChannelArgs& /*channel_args*/) {
560                            return true;
561                          })));
562   SendRPC();
563   const char* kMetricName = "grpc.server.call.duration";
564   auto data = ReadCurrentMetricsData(
565       [&](const absl::flat_hash_map<
566           std::string,
567           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
568               data) { return !data.contains(kMetricName); });
569   ASSERT_EQ(data[kMetricName].size(), 1);
570   const auto& server_attributes =
571       data[kMetricName][0].attributes.GetAttributes();
572   EXPECT_EQ(server_attributes.size(), 2);
573   EXPECT_EQ(absl::get<std::string>(server_attributes.at("grpc.method")),
574             kMethodName);
575   EXPECT_EQ(absl::get<std::string>(server_attributes.at("grpc.status")), "OK");
576 }
577 
578 // Test that a server selector returning false does not record metrics on the
579 // server.
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerSelectorReturnsFalse)580 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerSelectorReturnsFalse) {
581   Init(std::move(Options()
582                      .set_metric_names({grpc::OpenTelemetryPluginBuilder::
583                                             kServerCallDurationInstrumentName})
584                      .set_server_selector(
585                          [](const grpc_core::ChannelArgs& /*channel_args*/) {
586                            return false;
587                          })));
588   SendRPC();
589   auto data = ReadCurrentMetricsData(
590       [&](const absl::flat_hash_map<
591           std::string,
592           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
593           /*data*/) { return false; });
594   ASSERT_TRUE(data.empty());
595 }
596 
597 // Test that a target attribute filter returning true records metrics with the
598 // target as is on the channel.
TEST_F(OpenTelemetryPluginEnd2EndTest,TargetAttributeFilterReturnsTrue)599 TEST_F(OpenTelemetryPluginEnd2EndTest, TargetAttributeFilterReturnsTrue) {
600   Init(
601       std::move(Options()
602                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
603                                            kClientAttemptStartedInstrumentName})
604                     .set_target_attribute_filter(
605                         [](absl::string_view /*target*/) { return true; })));
606   SendRPC();
607   const char* kMetricName = "grpc.client.attempt.started";
608   auto data = ReadCurrentMetricsData(
609       [&](const absl::flat_hash_map<
610           std::string,
611           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
612               data) { return !data.contains(kMetricName); });
613   ASSERT_EQ(data[kMetricName].size(), 1);
614   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
615       &data[kMetricName][0].point_data);
616   ASSERT_NE(point_data, nullptr);
617   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
618   ASSERT_NE(client_started_value, nullptr);
619   EXPECT_EQ(*client_started_value, 1);
620   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
621   EXPECT_EQ(attributes.size(), 2);
622   const auto* method_value =
623       absl::get_if<std::string>(&attributes.at("grpc.method"));
624   ASSERT_NE(method_value, nullptr);
625   EXPECT_EQ(*method_value, kMethodName);
626   const auto* target_value =
627       absl::get_if<std::string>(&attributes.at("grpc.target"));
628   ASSERT_NE(target_value, nullptr);
629   EXPECT_EQ(*target_value, canonical_server_address_);
630 }
631 
632 // Test that a target attribute filter returning false records metrics with the
633 // target as "other".
TEST_F(OpenTelemetryPluginEnd2EndTest,TargetAttributeFilterReturnsFalse)634 TEST_F(OpenTelemetryPluginEnd2EndTest, TargetAttributeFilterReturnsFalse) {
635   Init(
636       std::move(Options()
637                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
638                                            kClientAttemptStartedInstrumentName})
639                     .set_target_attribute_filter(
640                         [](absl::string_view /*target*/) { return false; })));
641   SendRPC();
642   const char* kMetricName = "grpc.client.attempt.started";
643   auto data = ReadCurrentMetricsData(
644       [&](const absl::flat_hash_map<
645           std::string,
646           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
647           /*data*/) { return false; });
648   ASSERT_EQ(data[kMetricName].size(), 1);
649   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
650       &data[kMetricName][0].point_data);
651   ASSERT_NE(point_data, nullptr);
652   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
653   ASSERT_NE(client_started_value, nullptr);
654   EXPECT_EQ(*client_started_value, 1);
655   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
656   EXPECT_EQ(attributes.size(), 2);
657   const auto* method_value =
658       absl::get_if<std::string>(&attributes.at("grpc.method"));
659   ASSERT_NE(method_value, nullptr);
660   EXPECT_EQ(*method_value, kMethodName);
661   const auto* target_value =
662       absl::get_if<std::string>(&attributes.at("grpc.target"));
663   ASSERT_NE(target_value, nullptr);
664   EXPECT_EQ(*target_value, "other");
665 }
666 
667 // Test that generic method names are scrubbed properly on the client side.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericClientRpc)668 TEST_F(OpenTelemetryPluginEnd2EndTest, GenericClientRpc) {
669   Init(std::move(
670       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
671                                       kClientAttemptStartedInstrumentName})));
672   SendGenericRPC();
673   const char* kMetricName = "grpc.client.attempt.started";
674   auto data = ReadCurrentMetricsData(
675       [&](const absl::flat_hash_map<
676           std::string,
677           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
678           /*data*/) { return false; });
679   ASSERT_EQ(data[kMetricName].size(), 1);
680   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
681       &data[kMetricName][0].point_data);
682   ASSERT_NE(point_data, nullptr);
683   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
684   ASSERT_NE(client_started_value, nullptr);
685   EXPECT_EQ(*client_started_value, 1);
686   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
687   EXPECT_EQ(attributes.size(), 2);
688   const auto* method_value =
689       absl::get_if<std::string>(&attributes.at("grpc.method"));
690   ASSERT_NE(method_value, nullptr);
691   EXPECT_EQ(*method_value, "other");
692   const auto* target_value =
693       absl::get_if<std::string>(&attributes.at("grpc.target"));
694   ASSERT_NE(target_value, nullptr);
695   EXPECT_EQ(*target_value, canonical_server_address_);
696 }
697 
698 // Test that generic method names are scrubbed properly on the client side if
699 // the method attribute filter is set and it returns false.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericClientRpcWithMethodAttributeFilterReturningFalse)700 TEST_F(OpenTelemetryPluginEnd2EndTest,
701        GenericClientRpcWithMethodAttributeFilterReturningFalse) {
702   Init(std::move(
703       Options()
704           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
705                                  kClientAttemptStartedInstrumentName})
706           .set_generic_method_attribute_filter(
707               [](absl::string_view /*generic_method*/) { return false; })));
708   SendGenericRPC();
709   const char* kMetricName = "grpc.client.attempt.started";
710   auto data = ReadCurrentMetricsData(
711       [&](const absl::flat_hash_map<
712           std::string,
713           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
714           /*data*/) { return false; });
715   ASSERT_EQ(data[kMetricName].size(), 1);
716   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
717       &data[kMetricName][0].point_data);
718   ASSERT_NE(point_data, nullptr);
719   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
720   ASSERT_NE(client_started_value, nullptr);
721   EXPECT_EQ(*client_started_value, 1);
722   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
723   EXPECT_EQ(attributes.size(), 2);
724   const auto* method_value =
725       absl::get_if<std::string>(&attributes.at("grpc.method"));
726   ASSERT_NE(method_value, nullptr);
727   EXPECT_EQ(*method_value, "other");
728   const auto* target_value =
729       absl::get_if<std::string>(&attributes.at("grpc.target"));
730   ASSERT_NE(target_value, nullptr);
731   EXPECT_EQ(*target_value, canonical_server_address_);
732 }
733 
734 // Test that generic method names is not scrubbed on the client side if
735 // the method attribute filter is set and it returns true.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericClientRpcWithMethodAttributeFilterReturningTrue)736 TEST_F(OpenTelemetryPluginEnd2EndTest,
737        GenericClientRpcWithMethodAttributeFilterReturningTrue) {
738   Init(std::move(
739       Options()
740           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
741                                  kClientAttemptStartedInstrumentName})
742           .set_generic_method_attribute_filter(
743               [](absl::string_view /*generic_method*/) { return true; })));
744   SendGenericRPC();
745   const char* kMetricName = "grpc.client.attempt.started";
746   auto data = ReadCurrentMetricsData(
747       [&](const absl::flat_hash_map<
748           std::string,
749           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
750           /*data*/) { return false; });
751   ASSERT_EQ(data[kMetricName].size(), 1);
752   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
753       &data[kMetricName][0].point_data);
754   ASSERT_NE(point_data, nullptr);
755   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
756   ASSERT_NE(client_started_value, nullptr);
757   EXPECT_EQ(*client_started_value, 1);
758   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
759   EXPECT_EQ(attributes.size(), 2);
760   const auto* method_value =
761       absl::get_if<std::string>(&attributes.at("grpc.method"));
762   ASSERT_NE(method_value, nullptr);
763   EXPECT_EQ(*method_value, kGenericMethodName);
764   const auto* target_value =
765       absl::get_if<std::string>(&attributes.at("grpc.target"));
766   ASSERT_NE(target_value, nullptr);
767   EXPECT_EQ(*target_value, canonical_server_address_);
768 }
769 
770 // Test that generic method names are scrubbed properly on the server side.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericServerRpc)771 TEST_F(OpenTelemetryPluginEnd2EndTest, GenericServerRpc) {
772   Init(std::move(Options().set_metric_names(
773       {grpc::OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName})));
774   SendGenericRPC();
775   const char* kMetricName = "grpc.server.call.duration";
776   auto data = ReadCurrentMetricsData(
777       [&](const absl::flat_hash_map<
778           std::string,
779           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
780               data) { return !data.contains(kMetricName); });
781   ASSERT_EQ(data[kMetricName].size(), 1);
782   auto point_data =
783       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
784           &data[kMetricName][0].point_data);
785   ASSERT_NE(point_data, nullptr);
786   ASSERT_EQ(point_data->count_, 1);
787   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
788   EXPECT_EQ(attributes.size(), 2);
789   const auto* method_value =
790       absl::get_if<std::string>(&attributes.at("grpc.method"));
791   ASSERT_NE(method_value, nullptr);
792   EXPECT_EQ(*method_value, "other");
793   const auto* status_value =
794       absl::get_if<std::string>(&attributes.at("grpc.status"));
795   ASSERT_NE(status_value, nullptr);
796   EXPECT_EQ(*status_value, "UNIMPLEMENTED");
797 }
798 
799 // Test that generic method names are scrubbed properly on the server side if
800 // the method attribute filter is set and it returns false.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericServerRpcWithMethodAttributeFilterReturningFalse)801 TEST_F(OpenTelemetryPluginEnd2EndTest,
802        GenericServerRpcWithMethodAttributeFilterReturningFalse) {
803   Init(std::move(
804       Options()
805           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
806                                  kServerCallDurationInstrumentName})
807           .set_generic_method_attribute_filter(
808               [](absl::string_view /*generic_method*/) { return false; })));
809   SendGenericRPC();
810   const char* kMetricName = "grpc.server.call.duration";
811   auto data = ReadCurrentMetricsData(
812       [&](const absl::flat_hash_map<
813           std::string,
814           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
815               data) { return !data.contains(kMetricName); });
816   ASSERT_EQ(data[kMetricName].size(), 1);
817   auto point_data =
818       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
819           &data[kMetricName][0].point_data);
820   ASSERT_NE(point_data, nullptr);
821   ASSERT_EQ(point_data->count_, 1);
822   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
823   EXPECT_EQ(attributes.size(), 2);
824   const auto* method_value =
825       absl::get_if<std::string>(&attributes.at("grpc.method"));
826   ASSERT_NE(method_value, nullptr);
827   EXPECT_EQ(*method_value, "other");
828   const auto* status_value =
829       absl::get_if<std::string>(&attributes.at("grpc.status"));
830   ASSERT_NE(status_value, nullptr);
831   EXPECT_EQ(*status_value, "UNIMPLEMENTED");
832 }
833 
834 // Test that generic method names are not scrubbed on the server side if
835 // the method attribute filter is set and it returns true.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericServerRpcWithMethodAttributeFilterReturningTrue)836 TEST_F(OpenTelemetryPluginEnd2EndTest,
837        GenericServerRpcWithMethodAttributeFilterReturningTrue) {
838   Init(std::move(
839       Options()
840           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
841                                  kServerCallDurationInstrumentName})
842           .set_generic_method_attribute_filter(
843               [](absl::string_view /*generic_method*/) { return true; })));
844   SendGenericRPC();
845   const char* kMetricName = "grpc.server.call.duration";
846   auto data = ReadCurrentMetricsData(
847       [&](const absl::flat_hash_map<
848           std::string,
849           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
850               data) { return !data.contains(kMetricName); });
851   ASSERT_EQ(data[kMetricName].size(), 1);
852   auto point_data =
853       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
854           &data[kMetricName][0].point_data);
855   ASSERT_NE(point_data, nullptr);
856   ASSERT_EQ(point_data->count_, 1);
857   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
858   EXPECT_EQ(attributes.size(), 2);
859   const auto* method_value =
860       absl::get_if<std::string>(&attributes.at("grpc.method"));
861   ASSERT_NE(method_value, nullptr);
862   EXPECT_EQ(*method_value, kGenericMethodName);
863   const auto* status_value =
864       absl::get_if<std::string>(&attributes.at("grpc.status"));
865   ASSERT_NE(status_value, nullptr);
866   EXPECT_EQ(*status_value, "UNIMPLEMENTED");
867 }
868 
TEST_F(OpenTelemetryPluginEnd2EndTest,OptionalPerCallLocalityLabel)869 TEST_F(OpenTelemetryPluginEnd2EndTest, OptionalPerCallLocalityLabel) {
870   Init(
871       std::move(Options()
872                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
873                                            kClientAttemptStartedInstrumentName,
874                                        grpc::OpenTelemetryPluginBuilder::
875                                            kClientAttemptDurationInstrumentName,
876                                        grpc::OpenTelemetryPluginBuilder::
877                                            kServerCallStartedInstrumentName,
878                                        grpc::OpenTelemetryPluginBuilder::
879                                            kServerCallDurationInstrumentName})
880                     .add_optional_label("grpc.lb.locality")
881                     .set_labels_to_inject(
882                         {{grpc_core::ClientCallTracer::CallAttemptTracer::
883                               OptionalLabelKey::kLocality,
884                           grpc_core::RefCountedStringValue("locality")}})));
885   SendRPC();
886   auto data = ReadCurrentMetricsData(
887       [&](const absl::flat_hash_map<
888           std::string,
889           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
890               data) {
891         return !data.contains("grpc.client.attempt.started") ||
892                !data.contains("grpc.client.attempt.duration") ||
893                !data.contains("grpc.server.call.started") ||
894                !data.contains("grpc.server.call.duration");
895       });
896   // Verify client side metric (grpc.client.attempt.started) does not sees this
897   // label
898   ASSERT_EQ(data["grpc.client.attempt.started"].size(), 1);
899   const auto& client_attributes =
900       data["grpc.client.attempt.started"][0].attributes.GetAttributes();
901   EXPECT_THAT(
902       client_attributes,
903       ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
904   // Verify client side metric (grpc.client.attempt.duration) sees this label.
905   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
906   const auto& client_duration_attributes =
907       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
908   EXPECT_EQ(
909       absl::get<std::string>(client_duration_attributes.at("grpc.lb.locality")),
910       "locality");
911   // Verify server metric (grpc.server.call.started) does not see this label
912   ASSERT_EQ(data["grpc.server.call.started"].size(), 1);
913   const auto& server_attributes =
914       data["grpc.server.call.started"][0].attributes.GetAttributes();
915   EXPECT_THAT(
916       server_attributes,
917       ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
918   // Verify server metric (grpc.server.call.duration) does not see this label
919   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
920   const auto& server_duration_attributes =
921       data["grpc.server.call.duration"][0].attributes.GetAttributes();
922   EXPECT_THAT(
923       server_duration_attributes,
924       ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
925 }
926 
927 // Tests that when locality label is enabled on the plugin but not provided by
928 // gRPC, an empty value is recorded.
TEST_F(OpenTelemetryPluginEnd2EndTest,OptionalPerCallLocalityLabelWhenNotAvailable)929 TEST_F(OpenTelemetryPluginEnd2EndTest,
930        OptionalPerCallLocalityLabelWhenNotAvailable) {
931   Init(std::move(
932       Options()
933           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
934                                  kClientAttemptDurationInstrumentName})
935           .add_optional_label("grpc.lb.locality")));
936   SendRPC();
937   auto data = ReadCurrentMetricsData(
938       [&](const absl::flat_hash_map<
939           std::string,
940           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
941               data) { return !data.contains("grpc.client.attempt.duration"); });
942   // Verify client side metric (grpc.client.attempt.duration) sees the empty
943   // label value.
944   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
945   const auto& client_duration_attributes =
946       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
947   EXPECT_EQ(
948       absl::get<std::string>(client_duration_attributes.at("grpc.lb.locality")),
949       "");
950 }
951 
952 // Tests that when locality label is injected but not enabled by the plugin, the
953 // label is not recorded.
TEST_F(OpenTelemetryPluginEnd2EndTest,OptionalPerCallLocalityLabelNotRecordedWhenNotEnabled)954 TEST_F(OpenTelemetryPluginEnd2EndTest,
955        OptionalPerCallLocalityLabelNotRecordedWhenNotEnabled) {
956   Init(std::move(
957       Options()
958           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
959                                  kClientAttemptDurationInstrumentName})
960           .set_labels_to_inject(
961               {{grpc_core::ClientCallTracer::CallAttemptTracer::
962                     OptionalLabelKey::kLocality,
963                 grpc_core::RefCountedStringValue("locality")}})));
964   SendRPC();
965   auto data = ReadCurrentMetricsData(
966       [&](const absl::flat_hash_map<
967           std::string,
968           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
969               data) { return !data.contains("grpc.client.attempt.duration"); });
970   // Verify client side metric (grpc.client.attempt.duration) does not see the
971   // locality label.
972   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
973   const auto& client_duration_attributes =
974       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
975   EXPECT_THAT(
976       client_duration_attributes,
977       ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
978 }
979 
TEST_F(OpenTelemetryPluginEnd2EndTest,UnknownLabelDoesNotShowOnPerCallMetrics)980 TEST_F(OpenTelemetryPluginEnd2EndTest,
981        UnknownLabelDoesNotShowOnPerCallMetrics) {
982   Init(
983       std::move(Options()
984                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
985                                            kClientAttemptStartedInstrumentName,
986                                        grpc::OpenTelemetryPluginBuilder::
987                                            kClientAttemptDurationInstrumentName,
988                                        grpc::OpenTelemetryPluginBuilder::
989                                            kServerCallStartedInstrumentName,
990                                        grpc::OpenTelemetryPluginBuilder::
991                                            kServerCallDurationInstrumentName})
992                     .add_optional_label("unknown")));
993   SendRPC();
994   auto data = ReadCurrentMetricsData(
995       [&](const absl::flat_hash_map<
996           std::string,
997           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
998               data) {
999         return !data.contains("grpc.client.attempt.started") ||
1000                !data.contains("grpc.client.attempt.duration") ||
1001                !data.contains("grpc.server.call.started") ||
1002                !data.contains("grpc.server.call.duration");
1003       });
1004   // Verify client side metric (grpc.client.attempt.started) does not sees this
1005   // label
1006   ASSERT_EQ(data["grpc.client.attempt.started"].size(), 1);
1007   const auto& client_attributes =
1008       data["grpc.client.attempt.started"][0].attributes.GetAttributes();
1009   EXPECT_THAT(client_attributes,
1010               ::testing::Not(::testing::Contains(::testing::Key("unknown"))));
1011   // Verify client side metric (grpc.client.attempt.duration) does not see this
1012   // label
1013   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1014   const auto& client_duration_attributes =
1015       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1016   EXPECT_THAT(client_duration_attributes,
1017               ::testing::Not(::testing::Contains(::testing::Key("unknown"))));
1018   // Verify server metric (grpc.server.call.started) does not see this label
1019   ASSERT_EQ(data["grpc.server.call.started"].size(), 1);
1020   const auto& server_attributes =
1021       data["grpc.server.call.started"][0].attributes.GetAttributes();
1022   EXPECT_THAT(
1023       server_attributes,
1024       ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
1025   // Verify server metric (grpc.server.call.duration) does not see this label
1026   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1027   const auto& server_duration_attributes =
1028       data["grpc.server.call.duration"][0].attributes.GetAttributes();
1029   EXPECT_THAT(server_duration_attributes,
1030               ::testing::Not(::testing::Contains(::testing::Key("unknown"))));
1031 }
1032 
1033 using OpenTelemetryPluginOptionEnd2EndTest = OpenTelemetryPluginEnd2EndTest;
1034 
1035 class SimpleLabelIterable : public grpc::internal::LabelsIterable {
1036  public:
SimpleLabelIterable(std::pair<absl::string_view,absl::string_view> label)1037   explicit SimpleLabelIterable(
1038       std::pair<absl::string_view, absl::string_view> label)
1039       : label_(label) {}
1040 
Next()1041   absl::optional<std::pair<absl::string_view, absl::string_view>> Next()
1042       override {
1043     if (iterated_) {
1044       return absl::nullopt;
1045     }
1046     iterated_ = true;
1047     return label_;
1048   }
1049 
Size() const1050   size_t Size() const override { return 1; }
1051 
ResetIteratorPosition()1052   void ResetIteratorPosition() override { iterated_ = false; }
1053 
1054  private:
1055   bool iterated_ = false;
1056   std::pair<absl::string_view, absl::string_view> label_;
1057 };
1058 
1059 class CustomLabelInjector : public grpc::internal::LabelsInjector {
1060  public:
CustomLabelInjector(std::pair<std::string,std::string> label)1061   explicit CustomLabelInjector(std::pair<std::string, std::string> label)
1062       : label_(std::move(label)) {}
~CustomLabelInjector()1063   ~CustomLabelInjector() override {}
1064 
GetLabels(grpc_metadata_batch *) const1065   std::unique_ptr<grpc::internal::LabelsIterable> GetLabels(
1066       grpc_metadata_batch* /*incoming_initial_metadata*/) const override {
1067     return std::make_unique<SimpleLabelIterable>(label_);
1068   }
1069 
AddLabels(grpc_metadata_batch *,grpc::internal::LabelsIterable *) const1070   void AddLabels(
1071       grpc_metadata_batch* /*outgoing_initial_metadata*/,
1072       grpc::internal::LabelsIterable* /*labels_from_incoming_metadata*/)
1073       const override {}
1074 
AddOptionalLabels(bool,absl::Span<const grpc_core::RefCountedStringValue>,opentelemetry::nostd::function_ref<bool (opentelemetry::nostd::string_view,opentelemetry::common::AttributeValue)>) const1075   bool AddOptionalLabels(bool /*is_client*/,
1076                          absl::Span<const grpc_core::RefCountedStringValue>
1077                          /*optional_labels*/,
1078                          opentelemetry::nostd::function_ref<
1079                              bool(opentelemetry::nostd::string_view,
1080                                   opentelemetry::common::AttributeValue)>
1081                          /*callback*/) const override {
1082     return true;
1083   }
1084 
GetOptionalLabelsSize(bool,absl::Span<const grpc_core::RefCountedStringValue>) const1085   size_t GetOptionalLabelsSize(
1086       bool /*is_client*/, absl::Span<const grpc_core::RefCountedStringValue>
1087       /*optional_labels_span*/) const override {
1088     return 0;
1089   }
1090 
1091  private:
1092   std::pair<std::string, std::string> label_;
1093 };
1094 
1095 class CustomPluginOption
1096     : public grpc::internal::InternalOpenTelemetryPluginOption {
1097  public:
CustomPluginOption(bool enabled_on_client,bool enabled_on_server,std::pair<std::string,std::string> label)1098   CustomPluginOption(bool enabled_on_client, bool enabled_on_server,
1099                      std::pair<std::string, std::string> label)
1100       : enabled_on_client_(enabled_on_client),
1101         enabled_on_server_(enabled_on_server),
1102         label_injector_(
1103             std::make_unique<CustomLabelInjector>(std::move(label))) {}
1104 
~CustomPluginOption()1105   ~CustomPluginOption() override {}
1106 
IsActiveOnClientChannel(absl::string_view) const1107   bool IsActiveOnClientChannel(absl::string_view /*target*/) const override {
1108     return enabled_on_client_;
1109   }
1110 
IsActiveOnServer(const grpc_core::ChannelArgs &) const1111   bool IsActiveOnServer(const grpc_core::ChannelArgs& /*args*/) const override {
1112     return enabled_on_server_;
1113   }
1114 
labels_injector() const1115   const grpc::internal::LabelsInjector* labels_injector() const override {
1116     return label_injector_.get();
1117   }
1118 
1119  private:
1120   bool enabled_on_client_;
1121   bool enabled_on_server_;
1122   std::unique_ptr<CustomLabelInjector> label_injector_;
1123 };
1124 
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,Basic)1125 TEST_F(OpenTelemetryPluginOptionEnd2EndTest, Basic) {
1126   Init(
1127       std::move(Options()
1128                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1129                                            kClientAttemptDurationInstrumentName,
1130                                        grpc::OpenTelemetryPluginBuilder::
1131                                            kServerCallDurationInstrumentName})
1132                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1133                         /*enabled_on_client*/ true, /*enabled_on_server*/ true,
1134                         std::make_pair("key", "value")))));
1135   SendRPC();
1136   auto data = ReadCurrentMetricsData(
1137       [&](const absl::flat_hash_map<
1138           std::string,
1139           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1140               data) {
1141         return !data.contains("grpc.client.attempt.duration") ||
1142                !data.contains("grpc.server.call.duration");
1143       });
1144   // Verify client side metric
1145   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1146   const auto& client_attributes =
1147       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1148   EXPECT_EQ(client_attributes.size(), 4);
1149   EXPECT_EQ(absl::get<std::string>(client_attributes.at("key")), "value");
1150   // Verify server side metric
1151   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1152   const auto& server_attributes =
1153       data["grpc.server.call.duration"][0].attributes.GetAttributes();
1154   EXPECT_EQ(server_attributes.size(), 3);
1155   EXPECT_EQ(absl::get<std::string>(server_attributes.at("key")), "value");
1156 }
1157 
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,ClientOnlyPluginOption)1158 TEST_F(OpenTelemetryPluginOptionEnd2EndTest, ClientOnlyPluginOption) {
1159   Init(
1160       std::move(Options()
1161                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1162                                            kClientAttemptDurationInstrumentName,
1163                                        grpc::OpenTelemetryPluginBuilder::
1164                                            kServerCallDurationInstrumentName})
1165                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1166                         /*enabled_on_client*/ true, /*enabled_on_server*/ false,
1167                         std::make_pair("key", "value")))));
1168   SendRPC();
1169   auto data = ReadCurrentMetricsData(
1170       [&](const absl::flat_hash_map<
1171           std::string,
1172           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1173               data) {
1174         return !data.contains("grpc.client.attempt.duration") ||
1175                !data.contains("grpc.server.call.duration");
1176       });
1177   // Verify client side metric
1178   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1179   const auto& client_attributes =
1180       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1181   EXPECT_EQ(client_attributes.size(), 4);
1182   EXPECT_EQ(absl::get<std::string>(client_attributes.at("key")), "value");
1183   // Verify server side metric
1184   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1185   const auto& server_attributes =
1186       data["grpc.server.call.duration"][0].attributes.GetAttributes();
1187   EXPECT_EQ(server_attributes.size(), 2);
1188   EXPECT_THAT(server_attributes,
1189               ::testing::Not(::testing::Contains(::testing::Key("key"))));
1190 }
1191 
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,ServerOnlyPluginOption)1192 TEST_F(OpenTelemetryPluginOptionEnd2EndTest, ServerOnlyPluginOption) {
1193   Init(
1194       std::move(Options()
1195                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1196                                            kClientAttemptDurationInstrumentName,
1197                                        grpc::OpenTelemetryPluginBuilder::
1198                                            kServerCallDurationInstrumentName})
1199                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1200                         /*enabled_on_client*/ false, /*enabled_on_server*/ true,
1201                         std::make_pair("key", "value")))));
1202   SendRPC();
1203   auto data = ReadCurrentMetricsData(
1204       [&](const absl::flat_hash_map<
1205           std::string,
1206           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1207               data) {
1208         return !data.contains("grpc.client.attempt.duration") ||
1209                !data.contains("grpc.server.call.duration");
1210       });
1211   // Verify client side metric
1212   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1213   const auto& attributes =
1214       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1215   EXPECT_EQ(attributes.size(), 3);
1216   EXPECT_THAT(attributes,
1217               ::testing::Not(::testing::Contains(::testing::Key("key"))));
1218   // Verify server side metric
1219   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1220   const auto& server_attributes =
1221       data["grpc.server.call.duration"][0].attributes.GetAttributes();
1222   EXPECT_EQ(server_attributes.size(), 3);
1223   EXPECT_EQ(absl::get<std::string>(server_attributes.at("key")), "value");
1224 }
1225 
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,MultipleEnabledAndDisabledPluginOptions)1226 TEST_F(OpenTelemetryPluginOptionEnd2EndTest,
1227        MultipleEnabledAndDisabledPluginOptions) {
1228   Init(
1229       std::move(Options()
1230                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1231                                            kClientAttemptDurationInstrumentName,
1232                                        grpc::OpenTelemetryPluginBuilder::
1233                                            kServerCallDurationInstrumentName})
1234                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1235                         /*enabled_on_client*/ true, /*enabled_on_server*/ true,
1236                         std::make_pair("key1", "value1")))
1237                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1238                         /*enabled_on_client*/ true, /*enabled_on_server*/ false,
1239                         std::make_pair("key2", "value2")))
1240                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1241                         /*enabled_on_client*/ true, /*enabled_on_server*/ false,
1242                         std::make_pair("key3", "value3")))
1243                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1244                         /*enabled_on_client*/ false, /*enabled_on_server*/ true,
1245                         std::make_pair("key4", "value4")))
1246                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1247                         /*enabled_on_client*/ false, /*enabled_on_server*/ true,
1248                         std::make_pair("key5", "value5")))));
1249   SendRPC();
1250   auto data = ReadCurrentMetricsData(
1251       [&](const absl::flat_hash_map<
1252           std::string,
1253           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1254               data) {
1255         return !data.contains("grpc.client.attempt.duration") ||
1256                !data.contains("grpc.server.call.duration");
1257       });
1258   // Verify client side metric
1259   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1260   const auto& client_attributes =
1261       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1262   EXPECT_EQ(client_attributes.size(), 6);
1263   EXPECT_EQ(absl::get<std::string>(client_attributes.at("key1")), "value1");
1264   EXPECT_EQ(absl::get<std::string>(client_attributes.at("key2")), "value2");
1265   EXPECT_EQ(absl::get<std::string>(client_attributes.at("key3")), "value3");
1266   EXPECT_THAT(client_attributes,
1267               ::testing::Not(::testing::Contains(::testing::Key("key4"))));
1268   EXPECT_THAT(client_attributes,
1269               ::testing::Not(::testing::Contains(::testing::Key("key5"))));
1270   // Verify server side metric
1271   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1272   const auto& server_attributes =
1273       data["grpc.server.call.duration"][0].attributes.GetAttributes();
1274   EXPECT_EQ(server_attributes.size(), 5);
1275   EXPECT_EQ(absl::get<std::string>(server_attributes.at("key1")), "value1");
1276   EXPECT_THAT(server_attributes,
1277               ::testing::Not(::testing::Contains(::testing::Key("key2"))));
1278   EXPECT_THAT(server_attributes,
1279               ::testing::Not(::testing::Contains(::testing::Key("key3"))));
1280   EXPECT_EQ(absl::get<std::string>(server_attributes.at("key4")), "value4");
1281   EXPECT_EQ(absl::get<std::string>(server_attributes.at("key5")), "value5");
1282 }
1283 
1284 using OpenTelemetryPluginNPCMetricsTest = OpenTelemetryPluginEnd2EndTest;
1285 
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordUInt64Counter)1286 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordUInt64Counter) {
1287   constexpr absl::string_view kMetricName = "uint64_counter";
1288   constexpr int kCounterValues[] = {1, 2, 3};
1289   constexpr int64_t kCounterResult = 6;
1290   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1291                                                            "label_key_2"};
1292   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1293       "optional_label_key_1", "optional_label_key_2"};
1294   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1295                                                              "label_value_2"};
1296   constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1297       "optional_label_value_1", "optional_label_value_2"};
1298   auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterUInt64Counter(
1299       kMetricName, "A simple uint64 counter.", "unit", kLabelKeys,
1300       kOptionalLabelKeys, /*enable_by_default=*/true);
1301   Init(std::move(Options()
1302                      .set_metric_names({kMetricName})
1303                      .set_channel_scope_filter(
1304                          [](const OpenTelemetryPluginBuilder::ChannelScope&
1305                                 channel_scope) {
1306                            return absl::StartsWith(channel_scope.target(),
1307                                                    "dns:///");
1308                          })
1309                      .add_optional_label(kOptionalLabelKeys[0])
1310                      .add_optional_label(kOptionalLabelKeys[1])));
1311   auto stats_plugins =
1312       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1313           grpc_core::experimental::StatsPluginChannelScope(
1314               "dns:///localhost:8080", ""));
1315   for (auto v : kCounterValues) {
1316     stats_plugins.AddCounter(handle, v, kLabelValues, kOptionalLabelValues);
1317   }
1318   auto data = ReadCurrentMetricsData(
1319       [&](const absl::flat_hash_map<
1320           std::string,
1321           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1322               data) { return !data.contains(kMetricName); });
1323   EXPECT_THAT(data,
1324               ::testing::ElementsAre(::testing::Pair(
1325                   kMetricName,
1326                   ::testing::ElementsAre(::testing::AllOf(
1327                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1328                                    kOptionalLabelValues),
1329                       CounterResultEq(::testing::Eq(kCounterResult)))))));
1330 }
1331 
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordDoubleCounter)1332 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordDoubleCounter) {
1333   constexpr absl::string_view kMetricName = "double_counter";
1334   constexpr double kCounterValues[] = {1.23, 2.34, 3.45};
1335   constexpr double kCounterResult = 7.02;
1336   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1337                                                            "label_key_2"};
1338   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1339       "optional_label_key_1", "optional_label_key_2"};
1340   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1341                                                              "label_value_2"};
1342   constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1343       "optional_label_value_1", "optional_label_value_2"};
1344   auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleCounter(
1345       kMetricName, "A simple double counter.", "unit", kLabelKeys,
1346       kOptionalLabelKeys, /*enable_by_default=*/false);
1347   Init(std::move(Options()
1348                      .set_metric_names({kMetricName})
1349                      .set_channel_scope_filter(
1350                          [](const OpenTelemetryPluginBuilder::ChannelScope&
1351                                 channel_scope) {
1352                            return absl::StartsWith(channel_scope.target(),
1353                                                    "dns:///");
1354                          })
1355                      .add_optional_label(kOptionalLabelKeys[0])
1356                      .add_optional_label(kOptionalLabelKeys[1])));
1357   auto stats_plugins =
1358       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1359           grpc_core::experimental::StatsPluginChannelScope(
1360               "dns:///localhost:8080", ""));
1361   for (auto v : kCounterValues) {
1362     stats_plugins.AddCounter(handle, v, kLabelValues, kOptionalLabelValues);
1363   }
1364   auto data = ReadCurrentMetricsData(
1365       [&](const absl::flat_hash_map<
1366           std::string,
1367           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1368               data) { return !data.contains(kMetricName); });
1369   EXPECT_THAT(data,
1370               ::testing::ElementsAre(::testing::Pair(
1371                   kMetricName,
1372                   ::testing::ElementsAre(::testing::AllOf(
1373                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1374                                    kOptionalLabelValues),
1375                       CounterResultEq(::testing::DoubleEq(kCounterResult)))))));
1376 }
1377 
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordUInt64Histogram)1378 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordUInt64Histogram) {
1379   constexpr absl::string_view kMetricName = "uint64_histogram";
1380   constexpr int kHistogramValues[] = {1, 1, 2, 3, 4, 4, 5, 6};
1381   constexpr int64_t kSum = 26;
1382   constexpr int64_t kMin = 1;
1383   constexpr int64_t kMax = 6;
1384   constexpr int64_t kCount = 8;
1385   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1386                                                            "label_key_2"};
1387   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1388       "optional_label_key_1", "optional_label_key_2"};
1389   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1390                                                              "label_value_2"};
1391   constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1392       "optional_label_value_1", "optional_label_value_2"};
1393   auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterUInt64Histogram(
1394       kMetricName, "A simple uint64 histogram.", "unit", kLabelKeys,
1395       kOptionalLabelKeys, /*enable_by_default=*/true);
1396   Init(std::move(
1397       Options()
1398           .set_metric_names({kMetricName})
1399           .set_server_selector([](const grpc_core::ChannelArgs& args) {
1400             return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1401                    GRPC_ARG_SERVER_SELECTOR_VALUE;
1402           })
1403           .add_optional_label(kOptionalLabelKeys[0])
1404           .add_optional_label(kOptionalLabelKeys[1])));
1405   grpc_core::ChannelArgs args;
1406   args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1407   auto stats_plugins =
1408       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1409   for (auto v : kHistogramValues) {
1410     stats_plugins.RecordHistogram(handle, v, kLabelValues,
1411                                   kOptionalLabelValues);
1412   }
1413   auto data = ReadCurrentMetricsData(
1414       [&](const absl::flat_hash_map<
1415           std::string,
1416           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1417               data) { return !data.contains(kMetricName); });
1418   EXPECT_THAT(
1419       data, ::testing::ElementsAre(::testing::Pair(
1420                 kMetricName,
1421                 ::testing::ElementsAre(::testing::AllOf(
1422                     AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1423                                  kOptionalLabelValues),
1424                     HistogramResultEq(::testing::Eq(kSum), ::testing::Eq(kMin),
1425                                       ::testing::Eq(kMax), kCount))))));
1426 }
1427 
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordDoubleHistogram)1428 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordDoubleHistogram) {
1429   constexpr absl::string_view kMetricName = "double_histogram";
1430   constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
1431                                          4.4, 4.5, 5.5, 6.6};
1432   constexpr double kSum = 28.8;
1433   constexpr double kMin = 1.1;
1434   constexpr double kMax = 6.6;
1435   constexpr double kCount = 8;
1436   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1437                                                            "label_key_2"};
1438   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1439       "optional_label_key_1", "optional_label_key_2"};
1440   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1441                                                              "label_value_2"};
1442   constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1443       "optional_label_value_1", "optional_label_value_2"};
1444   auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
1445       kMetricName, "A simple double histogram.", "unit", kLabelKeys,
1446       kOptionalLabelKeys, /*enable_by_default=*/true);
1447   Init(std::move(
1448       Options()
1449           .set_metric_names({kMetricName})
1450           .set_server_selector([](const grpc_core::ChannelArgs& args) {
1451             return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1452                    GRPC_ARG_SERVER_SELECTOR_VALUE;
1453           })
1454           .add_optional_label(kOptionalLabelKeys[0])
1455           .add_optional_label(kOptionalLabelKeys[1])));
1456   grpc_core::ChannelArgs args;
1457   args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1458   auto stats_plugins =
1459       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1460   for (auto v : kHistogramValues) {
1461     stats_plugins.RecordHistogram(handle, v, kLabelValues,
1462                                   kOptionalLabelValues);
1463   }
1464   auto data = ReadCurrentMetricsData(
1465       [&](const absl::flat_hash_map<
1466           std::string,
1467           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1468               data) { return !data.contains(kMetricName); });
1469   EXPECT_THAT(data,
1470               ::testing::ElementsAre(::testing::Pair(
1471                   kMetricName,
1472                   ::testing::ElementsAre(::testing::AllOf(
1473                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1474                                    kOptionalLabelValues),
1475                       HistogramResultEq(::testing::DoubleEq(kSum),
1476                                         ::testing::DoubleEq(kMin),
1477                                         ::testing::DoubleEq(kMax), kCount))))));
1478 }
1479 
TEST_F(OpenTelemetryPluginNPCMetricsTest,RegisterMultipleOpenTelemetryPlugins)1480 TEST_F(OpenTelemetryPluginNPCMetricsTest,
1481        RegisterMultipleOpenTelemetryPlugins) {
1482   constexpr absl::string_view kMetricName = "yet_another_double_histogram";
1483   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1484                                                            "label_key_2"};
1485   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1486       "optional_label_key_1", "optional_label_key_2"};
1487   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1488                                                              "label_value_2"};
1489   constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1490       "optional_label_value_1", "optional_label_value_2"};
1491   auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
1492       kMetricName, "A simple double histogram.", "unit", kLabelKeys,
1493       kOptionalLabelKeys, /*enable_by_default=*/true);
1494   // Build and register a separate OpenTelemetryPlugin and verify its histogram
1495   // recording.
1496   grpc::internal::OpenTelemetryPluginBuilderImpl ot_builder;
1497   auto reader = BuildAndRegisterOpenTelemetryPlugin(std::move(
1498       Options()
1499           .set_metric_names({kMetricName})
1500           .set_server_selector([](const grpc_core::ChannelArgs& args) {
1501             return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1502                    GRPC_ARG_SERVER_SELECTOR_VALUE;
1503           })
1504           .add_optional_label(kOptionalLabelKeys[0])
1505           .add_optional_label(kOptionalLabelKeys[1])));
1506   EXPECT_EQ(ot_builder.BuildAndRegisterGlobal(), absl::OkStatus());
1507   grpc_core::ChannelArgs args;
1508   args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1509   {
1510     constexpr double kHistogramValues[] = {1.23, 2.34, 3.45, 4.56};
1511     constexpr double kSum = 11.58;
1512     constexpr double kMin = 1.23;
1513     constexpr double kMax = 4.56;
1514     constexpr int kCount = 4;
1515     auto stats_plugins =
1516         grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1517     for (auto v : kHistogramValues) {
1518       stats_plugins.RecordHistogram(handle, v, kLabelValues,
1519                                     kOptionalLabelValues);
1520     }
1521     auto data = ReadCurrentMetricsData(
1522         [&](const absl::flat_hash_map<
1523             std::string,
1524             std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1525                 data) { return !data.contains(kMetricName); },
1526         reader.get());
1527     EXPECT_THAT(
1528         data, ::testing::ElementsAre(::testing::Pair(
1529                   kMetricName,
1530                   ::testing::ElementsAre(::testing::AllOf(
1531                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1532                                    kOptionalLabelValues),
1533                       HistogramResultEq(::testing::DoubleEq(kSum),
1534                                         ::testing::DoubleEq(kMin),
1535                                         ::testing::DoubleEq(kMax), kCount))))));
1536   }
1537   // Now build and register another OpenTelemetryPlugin using the test fixture
1538   // and record histogram.
1539   constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
1540                                          4.4, 4.5, 5.5, 6.6};
1541   constexpr double kSum = 28.8;
1542   constexpr double kMin = 1.1;
1543   constexpr double kMax = 6.6;
1544   constexpr int kCount = 8;
1545   Init(std::move(
1546       Options()
1547           .set_metric_names({kMetricName})
1548           .set_server_selector([](const grpc_core::ChannelArgs& args) {
1549             return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1550                    GRPC_ARG_SERVER_SELECTOR_VALUE;
1551           })
1552           .add_optional_label(kOptionalLabelKeys[0])
1553           .add_optional_label(kOptionalLabelKeys[1])));
1554   auto stats_plugins =
1555       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1556   for (auto v : kHistogramValues) {
1557     stats_plugins.RecordHistogram(handle, v, kLabelValues,
1558                                   kOptionalLabelValues);
1559   }
1560   auto data = ReadCurrentMetricsData(
1561       [&](const absl::flat_hash_map<
1562           std::string,
1563           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1564               data) { return !data.contains(kMetricName); });
1565   EXPECT_THAT(data,
1566               ::testing::ElementsAre(::testing::Pair(
1567                   kMetricName,
1568                   ::testing::ElementsAre(::testing::AllOf(
1569                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1570                                    kOptionalLabelValues),
1571                       HistogramResultEq(::testing::DoubleEq(kSum),
1572                                         ::testing::DoubleEq(kMin),
1573                                         ::testing::DoubleEq(kMax), kCount))))));
1574   // Verify that the first plugin gets the data as well.
1575   data = ReadCurrentMetricsData(
1576       [&](const absl::flat_hash_map<
1577           std::string,
1578           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1579               data) { return !data.contains(kMetricName); },
1580       reader.get());
1581   EXPECT_THAT(data,
1582               ::testing::ElementsAre(::testing::Pair(
1583                   kMetricName,
1584                   ::testing::ElementsAre(::testing::AllOf(
1585                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1586                                    kOptionalLabelValues),
1587                       HistogramResultEq(::testing::DoubleEq(kSum),
1588                                         ::testing::DoubleEq(kMin),
1589                                         ::testing::DoubleEq(kMax), kCount))))));
1590 }
1591 
TEST_F(OpenTelemetryPluginNPCMetricsTest,DisabledOptionalLabelKeysShouldNotBeRecorded)1592 TEST_F(OpenTelemetryPluginNPCMetricsTest,
1593        DisabledOptionalLabelKeysShouldNotBeRecorded) {
1594   constexpr absl::string_view kMetricName =
1595       "yet_another_yet_another_double_histogram";
1596   constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
1597                                          4.4, 4.5, 5.5, 6.6};
1598   constexpr double kSum = 28.8;
1599   constexpr double kMin = 1.1;
1600   constexpr double kMax = 6.6;
1601   constexpr double kCount = 8;
1602   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1603                                                            "label_key_2"};
1604   constexpr std::array<absl::string_view, 4> kOptionalLabelKeys = {
1605       "optional_label_key_1", "optional_label_key_2", "optional_label_key_3",
1606       "optional_label_key_4"};
1607   constexpr std::array<absl::string_view, 3> kActualOptionalLabelKeys = {
1608       "optional_label_key_1", "optional_label_key_2", "optional_label_key_4"};
1609   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1610                                                              "label_value_2"};
1611   constexpr std::array<absl::string_view, 4> kOptionalLabelValues = {
1612       "optional_label_value_1", "optional_label_value_2",
1613       "optional_label_value_3", "optional_label_value_4"};
1614   constexpr std::array<absl::string_view, 3> kActualOptionalLabelValues = {
1615       "optional_label_value_1", "optional_label_value_2",
1616       "optional_label_value_4"};
1617   auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
1618       kMetricName, "A simple double histogram.", "unit", kLabelKeys,
1619       kOptionalLabelKeys, /*enable_by_default=*/true);
1620   Init(std::move(
1621       Options()
1622           .set_metric_names({kMetricName})
1623           .set_server_selector([](const grpc_core::ChannelArgs& args) {
1624             return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1625                    GRPC_ARG_SERVER_SELECTOR_VALUE;
1626           })
1627           .add_optional_label(kOptionalLabelKeys[0])
1628           .add_optional_label(kOptionalLabelKeys[1])
1629           .add_optional_label(kOptionalLabelKeys[3])));
1630   grpc_core::ChannelArgs args;
1631   args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1632   auto stats_plugins =
1633       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1634   for (auto v : kHistogramValues) {
1635     stats_plugins.RecordHistogram(handle, v, kLabelValues,
1636                                   kOptionalLabelValues);
1637   }
1638   auto data = ReadCurrentMetricsData(
1639       [&](const absl::flat_hash_map<
1640           std::string,
1641           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1642               data) { return !data.contains(kMetricName); });
1643   EXPECT_THAT(
1644       data,
1645       ::testing::ElementsAre(::testing::Pair(
1646           kMetricName,
1647           ::testing::ElementsAre(::testing::AllOf(
1648               AttributesEq(kLabelKeys, kLabelValues, kActualOptionalLabelKeys,
1649                            kActualOptionalLabelValues),
1650               HistogramResultEq(::testing::DoubleEq(kSum),
1651                                 ::testing::DoubleEq(kMin),
1652                                 ::testing::DoubleEq(kMax), kCount))))));
1653 }
1654 
1655 using OpenTelemetryPluginCallbackMetricsTest = OpenTelemetryPluginEnd2EndTest;
1656 
1657 // The callback minimal interval is longer than the OT reporting interval, so we
1658 // expect to collect duplicated (cached) values.
TEST_F(OpenTelemetryPluginCallbackMetricsTest,ReportDurationLongerThanCollectDuration)1659 TEST_F(OpenTelemetryPluginCallbackMetricsTest,
1660        ReportDurationLongerThanCollectDuration) {
1661   constexpr absl::string_view kInt64CallbackGaugeMetric =
1662       "int64_callback_gauge";
1663   constexpr absl::string_view kDoubleCallbackGaugeMetric =
1664       "double_callback_gauge";
1665   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1666                                                            "label_key_2"};
1667   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1668       "optional_label_key_1", "optional_label_key_2"};
1669   constexpr std::array<absl::string_view, 2> kLabelValuesSet1 = {
1670       "label_value_set_1", "label_value_set_1"};
1671   constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet1 = {
1672       "optional_label_value_set_1", "optional_label_value_set_1"};
1673   constexpr std::array<absl::string_view, 2> kLabelValuesSet2 = {
1674       "label_value_set_2", "label_value_set_2"};
1675   constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet2 = {
1676       "optional_label_value_set_2", "optional_label_value_set_2"};
1677   auto integer_gauge_handle =
1678       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
1679           kInt64CallbackGaugeMetric, "An int64 callback gauge.", "unit",
1680           kLabelKeys, kOptionalLabelKeys,
1681           /*enable_by_default=*/true);
1682   auto double_gauge_handle =
1683       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
1684           kDoubleCallbackGaugeMetric, "A double callback gauge.", "unit",
1685           kLabelKeys, kOptionalLabelKeys,
1686           /*enable_by_default=*/true);
1687   Init(std::move(Options()
1688                      .set_metric_names({kInt64CallbackGaugeMetric,
1689                                         kDoubleCallbackGaugeMetric})
1690                      .add_optional_label(kOptionalLabelKeys[0])
1691                      .add_optional_label(kOptionalLabelKeys[1])));
1692   auto stats_plugins =
1693       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1694           grpc_core::experimental::StatsPluginChannelScope(
1695               "dns:///localhost:8080", ""));
1696   // Multiple callbacks for the same metrics, each reporting different label
1697   // values.
1698   int report_count_1 = 0;
1699   int64_t int_value_1 = 1;
1700   double double_value_1 = 0.5;
1701   auto registered_metric_callback_1 = stats_plugins.RegisterCallback(
1702       [&](grpc_core::CallbackMetricReporter& reporter) {
1703         ++report_count_1;
1704         reporter.Report(integer_gauge_handle, int_value_1, kLabelValuesSet1,
1705                         kOptionalLabelValuesSet1);
1706         reporter.Report(integer_gauge_handle, int_value_1++, kLabelValuesSet2,
1707                         kOptionalLabelValuesSet2);
1708         reporter.Report(double_gauge_handle, double_value_1, kLabelValuesSet1,
1709                         kOptionalLabelValuesSet1);
1710         reporter.Report(double_gauge_handle, double_value_1++, kLabelValuesSet2,
1711                         kOptionalLabelValuesSet2);
1712       },
1713       {integer_gauge_handle, double_gauge_handle},
1714       grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor());
1715   int report_count_2 = 0;
1716   int64_t int_value_2 = 1;
1717   double double_value_2 = 0.5;
1718   auto registered_metric_callback_2 = stats_plugins.RegisterCallback(
1719       [&](grpc_core::CallbackMetricReporter& reporter) {
1720         ++report_count_2;
1721         reporter.Report(integer_gauge_handle, int_value_2, kLabelValuesSet1,
1722                         kOptionalLabelValuesSet1);
1723         reporter.Report(integer_gauge_handle, int_value_2++, kLabelValuesSet2,
1724                         kOptionalLabelValuesSet2);
1725         reporter.Report(double_gauge_handle, double_value_2, kLabelValuesSet1,
1726                         kOptionalLabelValuesSet1);
1727         reporter.Report(double_gauge_handle, double_value_2++, kLabelValuesSet2,
1728                         kOptionalLabelValuesSet2);
1729       },
1730       {integer_gauge_handle, double_gauge_handle},
1731       grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor());
1732   constexpr int kIterations = 100;
1733   MetricsCollectorThread collector{
1734       this, grpc_core::Duration::Milliseconds(10) * grpc_test_slowdown_factor(),
1735       kIterations,
1736       [&](const absl::flat_hash_map<
1737           std::string,
1738           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1739               data) {
1740         return !data.contains(kInt64CallbackGaugeMetric) ||
1741                !data.contains(kDoubleCallbackGaugeMetric);
1742       }};
1743   absl::flat_hash_map<
1744       std::string,
1745       std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>
1746       data = collector.Stop();
1747   // Verify that data is incremental with duplications (cached values).
1748   EXPECT_LT(report_count_1, kIterations);
1749   EXPECT_LT(report_count_2, kIterations);
1750   EXPECT_EQ(data[kInt64CallbackGaugeMetric].size(),
1751             data[kDoubleCallbackGaugeMetric].size());
1752   // Verify labels.
1753   ASSERT_THAT(
1754       data,
1755       ::testing::UnorderedElementsAre(
1756           ::testing::Pair(
1757               kInt64CallbackGaugeMetric,
1758               ::testing::Each(::testing::AnyOf(
1759                   AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1760                                kOptionalLabelValuesSet1),
1761                   AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1762                                kOptionalLabelValuesSet2)))),
1763           ::testing::Pair(
1764               kDoubleCallbackGaugeMetric,
1765               ::testing::Each(::testing::AnyOf(
1766                   AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1767                                kOptionalLabelValuesSet1),
1768                   AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1769                                kOptionalLabelValuesSet2))))));
1770   EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1771                         kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1772                         kOptionalLabelKeys, kOptionalLabelValuesSet1,
1773                         int64_t(0), false));
1774   EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1775                         kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1776                         kOptionalLabelKeys, kOptionalLabelValuesSet2,
1777                         int64_t(0), false));
1778   EXPECT_THAT(data,
1779               GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1780                   kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1781                   kOptionalLabelKeys, kOptionalLabelValuesSet1, 0.0, false));
1782   EXPECT_THAT(data,
1783               GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1784                   kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1785                   kOptionalLabelKeys, kOptionalLabelValuesSet2, 0.0, false));
1786 }
1787 
1788 // The callback minimal interval is shorter than the OT reporting interval, so
1789 // for each collect we should go update the cache and report the latest values.
TEST_F(OpenTelemetryPluginCallbackMetricsTest,ReportDurationShorterThanCollectDuration)1790 TEST_F(OpenTelemetryPluginCallbackMetricsTest,
1791        ReportDurationShorterThanCollectDuration) {
1792   constexpr absl::string_view kInt64CallbackGaugeMetric =
1793       "yet_another_int64_callback_gauge";
1794   constexpr absl::string_view kDoubleCallbackGaugeMetric =
1795       "yet_another_double_callback_gauge";
1796   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1797                                                            "label_key_2"};
1798   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1799       "optional_label_key_1", "optional_label_key_2"};
1800   constexpr std::array<absl::string_view, 2> kLabelValuesSet1 = {
1801       "label_value_set_1", "label_value_set_1"};
1802   constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet1 = {
1803       "optional_label_value_set_1", "optional_label_value_set_1"};
1804   constexpr std::array<absl::string_view, 2> kLabelValuesSet2 = {
1805       "label_value_set_2", "label_value_set_2"};
1806   constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet2 = {
1807       "optional_label_value_set_2", "optional_label_value_set_2"};
1808   auto integer_gauge_handle =
1809       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
1810           kInt64CallbackGaugeMetric, "An int64 callback gauge.", "unit",
1811           kLabelKeys, kOptionalLabelKeys,
1812           /*enable_by_default=*/true);
1813   auto double_gauge_handle =
1814       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
1815           kDoubleCallbackGaugeMetric, "A double callback gauge.", "unit",
1816           kLabelKeys, kOptionalLabelKeys,
1817           /*enable_by_default=*/true);
1818   Init(std::move(Options()
1819                      .set_metric_names({kInt64CallbackGaugeMetric,
1820                                         kDoubleCallbackGaugeMetric})
1821                      .add_optional_label(kOptionalLabelKeys[0])
1822                      .add_optional_label(kOptionalLabelKeys[1])));
1823   auto stats_plugins =
1824       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1825           grpc_core::experimental::StatsPluginChannelScope(
1826               "dns:///localhost:8080", ""));
1827   // Multiple callbacks for the same metrics, each reporting different label
1828   // values.
1829   int report_count_1 = 0;
1830   int64_t int_value_1 = 1;
1831   double double_value_1 = 0.5;
1832   auto registered_metric_callback_1 = stats_plugins.RegisterCallback(
1833       [&](grpc_core::CallbackMetricReporter& reporter) {
1834         ++report_count_1;
1835         reporter.Report(integer_gauge_handle, int_value_1, kLabelValuesSet1,
1836                         kOptionalLabelValuesSet1);
1837         reporter.Report(integer_gauge_handle, int_value_1++, kLabelValuesSet2,
1838                         kOptionalLabelValuesSet2);
1839         reporter.Report(double_gauge_handle, double_value_1, kLabelValuesSet1,
1840                         kOptionalLabelValuesSet1);
1841         reporter.Report(double_gauge_handle, double_value_1++, kLabelValuesSet2,
1842                         kOptionalLabelValuesSet2);
1843       },
1844       {integer_gauge_handle, double_gauge_handle},
1845       grpc_core::Duration::Milliseconds(10) * grpc_test_slowdown_factor());
1846   int report_count_2 = 0;
1847   int64_t int_value_2 = 1;
1848   double double_value_2 = 0.5;
1849   auto registered_metric_callback_2 = stats_plugins.RegisterCallback(
1850       [&](grpc_core::CallbackMetricReporter& reporter) {
1851         ++report_count_2;
1852         reporter.Report(integer_gauge_handle, int_value_2, kLabelValuesSet1,
1853                         kOptionalLabelValuesSet1);
1854         reporter.Report(integer_gauge_handle, int_value_2++, kLabelValuesSet2,
1855                         kOptionalLabelValuesSet2);
1856         reporter.Report(double_gauge_handle, double_value_2, kLabelValuesSet1,
1857                         kOptionalLabelValuesSet1);
1858         reporter.Report(double_gauge_handle, double_value_2++, kLabelValuesSet2,
1859                         kOptionalLabelValuesSet2);
1860       },
1861       {integer_gauge_handle, double_gauge_handle},
1862       grpc_core::Duration::Milliseconds(10) * grpc_test_slowdown_factor());
1863   constexpr int kIterations = 100;
1864   MetricsCollectorThread collector{
1865       this,
1866       grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
1867       kIterations,
1868       [&](const absl::flat_hash_map<
1869           std::string,
1870           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1871               data) {
1872         return !data.contains(kInt64CallbackGaugeMetric) ||
1873                !data.contains(kDoubleCallbackGaugeMetric);
1874       }};
1875   absl::flat_hash_map<
1876       std::string,
1877       std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>
1878       data = collector.Stop();
1879   // Verify that data is incremental without duplications (cached values).
1880   EXPECT_EQ(report_count_1, kIterations);
1881   EXPECT_EQ(report_count_2, kIterations);
1882   EXPECT_EQ(data[kInt64CallbackGaugeMetric].size(),
1883             data[kDoubleCallbackGaugeMetric].size());
1884   // Verify labels.
1885   ASSERT_THAT(
1886       data,
1887       ::testing::UnorderedElementsAre(
1888           ::testing::Pair(
1889               kInt64CallbackGaugeMetric,
1890               ::testing::Each(::testing::AnyOf(
1891                   AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1892                                kOptionalLabelValuesSet1),
1893                   AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1894                                kOptionalLabelValuesSet2)))),
1895           ::testing::Pair(
1896               kDoubleCallbackGaugeMetric,
1897               ::testing::Each(::testing::AnyOf(
1898                   AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1899                                kOptionalLabelValuesSet1),
1900                   AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1901                                kOptionalLabelValuesSet2))))));
1902   EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1903                         kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1904                         kOptionalLabelKeys, kOptionalLabelValuesSet1,
1905                         int64_t(0), true));
1906   EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1907                         kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1908                         kOptionalLabelKeys, kOptionalLabelValuesSet2,
1909                         int64_t(0), true));
1910   EXPECT_THAT(data,
1911               GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1912                   kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1913                   kOptionalLabelKeys, kOptionalLabelValuesSet1, 0.0, true));
1914   EXPECT_THAT(data,
1915               GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1916                   kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1917                   kOptionalLabelKeys, kOptionalLabelValuesSet2, 0.0, true));
1918 }
1919 
TEST(OpenTelemetryPluginMetricsEnablingDisablingTest,TestEnableDisableAPIs)1920 TEST(OpenTelemetryPluginMetricsEnablingDisablingTest, TestEnableDisableAPIs) {
1921   grpc::internal::OpenTelemetryPluginBuilderImpl builder;
1922   // First disable all metrics
1923   builder.DisableAllMetrics();
1924   EXPECT_TRUE(builder.TestOnlyEnabledMetrics().empty());
1925   // Add in a few metrics
1926   builder.EnableMetrics(
1927       {"grpc.test.metric_1", "grpc.test.metric_2", "grpc.test.metric_3"});
1928   EXPECT_THAT(
1929       builder.TestOnlyEnabledMetrics(),
1930       ::testing::UnorderedElementsAre(
1931           "grpc.test.metric_1", "grpc.test.metric_2", "grpc.test.metric_3"));
1932   // Now remove a few metrics
1933   builder.DisableMetrics({"grpc.test.metric_1", "grpc.test.metric_2"});
1934   EXPECT_THAT(builder.TestOnlyEnabledMetrics(),
1935               ::testing::UnorderedElementsAre("grpc.test.metric_3"));
1936 }
1937 
1938 }  // namespace
1939 }  // namespace testing
1940 }  // namespace grpc
1941 
main(int argc,char ** argv)1942 int main(int argc, char** argv) {
1943   grpc::testing::TestEnvironment env(&argc, argv);
1944   ::testing::InitGoogleTest(&argc, argv);
1945   return RUN_ALL_TESTS();
1946 }
1947